实验六二维裁剪Word文档下载推荐.docx
《实验六二维裁剪Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《实验六二维裁剪Word文档下载推荐.docx(11页珍藏版)》请在冰豆网上搜索。
在这个矩形方位之外定义的图形,不能被显示出来。
注意,当没有为应用程序指定裁剪窗口时,就使用默认的坐标:
xWinMin=-1.0,xWinMax=1.0,yWinMin=-1.0,yWinMax=1.0。
这样,默认的裁剪窗口是以坐标系原点为中心,边长为2的正方形区域。
那么,这个范围内的图形,显示在显示器上生成窗口的哪个位置呢?
这需要通过视区函数(ViewPort,有时也称视口)来指定:
glViewport(xViewportMin,xViewportMax,viewportWidth,viewportHeight);
这里的所有参数用对应于显示窗口的整数屏幕坐标给出,参数xViewportMin和yViewportMin指定视区左下角的位置,视区的宽度和高度用参数viewportWidth和viewportHeight指定。
也就是说,用gluOrtho2D指定显示范围的图形在用glViewport指定的窗口位置显示出来。
注意,当没有在应用程序中用glViewport指定视区时,则默认的视区大小及位置与整个OpenGL显示窗口一样。
显然,当gluOrtho2D和glViewport指定的矩形区域的宽高比不一样时,图形会发生形变。
那么,已经在世界坐标系中定义的物体,计算机的显示系统怎样确定哪些部分显示,哪些部分不显示呢?
这是通过相关的裁减算法计算出来的。
二、裁减算法
1、点的裁剪
判断点P=(x,y)是否在裁剪区域(xWinMin,xWinMax,yWinMin,yWinMax)内,只要判断是否满足条件
如果满足,就表明在裁剪区域内,否则,就在裁剪区域之外。
2、线段的裁减
线段的裁减要判断线段与裁剪矩形边界的各种关系。
经典的线段裁剪算法有Cohen-Sutherland算法和梁友栋-Barskey算法。
Cohen-Sutherland算法的代码如下:
classwcPt2D{
public:
GLfloatx,y;
};
inlineGLintround(constGLfloata){returnGLint(a+0.5);
}
/*Defineafour-bitcodeforeachoftheoutsideregionsofa
*rectangularclippingwindow.
*/
constGLintwinLeftBitCode=0x1;
constGLintwinRightBitCode=0x2;
constGLintwinBottomBitCode=0x4;
constGLintwinTopBitCode=0x8;
/*Abit-maskregioncodeisalsoassignedtoeachendpointofaninput
*linesegment,accordingtoitspositionrelativetothefouredgesof
*aninputrectangularclipwindow.
*
*Anendpointwitharegion-codevalueof0000isinsidetheclipping
*window,otherwiseitisoutsideatleastoneclippingboundary.If
*the'
or'
operationforthetwoendpointcodesproducesavalueof
*false,theentirelinedefinedbythesetwoendpointsissaved
*(accepted).Ifthe'
and'
operationbetweentwoendpointcodesis
*true,thelineiscompletelyoutsidetheclippingwindow,anditis
*eliminated(rejected)fromfurtherprocessing.
inlineGLintinside(GLintcode){returnGLint(!
code);
inlineGLintreject(GLintcode1,GLintcode2)
{returnGLint(code1&
code2);
inlineGLintaccept(GLintcode1,GLintcode2)
{returnGLint(!
(code1|code2));
GLubyteencode(wcPt2Dpt,wcPt2DwinMin,wcPt2DwinMax)
{
GLubytecode=0x00;
if(pt.x<
winMin.x)
code=code|winLeftBitCode;
if(pt.x>
winMax.x)
code=code|winRightBitCode;
if(pt.y<
winMin.y)
code=code|winBottomBitCode;
if(pt.y>
winMax.y)
code=code|winTopBitCode;
return(code);
}
voidswapPts(wcPt2D*p1,wcPt2D*p2)
wcPt2Dtmp;
tmp=*p1;
*p1=*p2;
*p2=tmp;
voidswapCodes(GLubyte*c1,GLubyte*c2)
GLubytetmp;
tmp=*c1;
*c1=*c2;
*c2=tmp;
voidlineClipCohSuth(wcPt2DwinMin,wcPt2DwinMax,wcPt2Dp1,wcPt2Dp2)
GLubytecode1,code2;
GLintdone=false,plotLine=false;
GLfloatm;
while(!
done){
code1=encode(p1,winMin,winMax);
code2=encode(p2,winMin,winMax);
if(accept(code1,code2)){
done=true;
plotLine=true;
else
if(reject(code1,code2))
else{
/*Labeltheendpointoutsidethedisplaywindowasp1.*/
if(inside(code1)){
swapPts(&
p1,&
p2);
swapCodes(&
code1,&
code2);
/*Useslopemtofindline-clipEdgeintersection.*/
if(p2.x!
=p1.x)
m=(p2.y-p1.y)/(p2.x-p1.x);
if(code1&
winLeftBitCode){
p1.y+=(winMin.x-p1.x)*m;
p1.x=winMin.x;
winRightBitCode){
p1.y+=(winMax.x-p1.x)*m;
p1.x=winMax.x;
winBottomBitCode){
/*Needtoupdatep1.xfornonverticallinesonly.*/
p1.x+=(winMin.y-p1.y)/m;
p1.y=winMin.y;
winTopBitCode){
p1.x+=(winMax.y-p1.y)/m;
p1.y=winMax.y;
if(plotLine)
lineBres(round(p1.x),round(p1.y),round(p2.x),round(p2.y));
//lineBres直线生成算法前面
添加以下的OpenGLglut的框架,并加上键盘控制,注意在把前面的Bresenham直线生成算法加到最前面:
voidmyDisplay()
wcPt2DwinMin,winMax,p1,p2;
winMin.x=100;
winMin.y=200;
//定义裁剪窗口
winMax.x=400;
winMax.y=400;
p1.x=50;
p1.y=50;
//定义被裁剪的直线端点
p2.x=450;
p2.y=450;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
glRectf(winMin.x,winMin.y,winMax.x,winMax.y);
//绘制红色裁剪矩形
glColor3f(1.0f,1.0f,1.0f);
if(flag)
{
lineClipCohSuth(winMin,winMax,p1,p2);
//绘制裁剪线段
glBegin(GL_LINES);
glVertex2i(p1.x,p1.y);
glVertex2i(p2.x,p2.y);
glEnd();
glFlush();
voidInit()
glClearColor(0.0,0.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,640.0,0.0,480.0);
voidReshape(intw,inth)
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);
voidkeyboard(unsignedcharkey,intx,inty)
if(key=='
c'
||key=='
C'
)flag=true;
r'
R'
)flag=false;
glutPostRedisplay();
intmain(intargc,char*argv[])
glutInit(&
argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(640,480);
glutCreateWindow("
Cohen-Sutherland直线裁减算法,C键裁减,R键复原"
);
Init();
glutDisplayFunc(myDisplay);
glutReshapeFunc(Reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return0;
梁友栋-Barskey算法的代码如下:
classwcPt2D
private:
/*DefaultConstructor:
initializepositionas(0.0,0.0).*/
wcPt2D(){
x=y=0.0;
voidsetCoords(GLfloatxCoord,GLfloatyCoord){
x=xCoord;
y=yCoord;
GLfloatgetx()const{
returnx;
GLfloatgety()const{
returny;
GLintclipTest(GLfloatp,GLfloatq,GLfloat*u1,GLfloat*u2)
GLfloatr;
GLintreturnValue=true;
if(p<
0.0){
r=q/p;
if(r>
*u2)
returnValue=false;
else
if(r>
*u1)
*u1=r;
if(p>
r=q/p;
if(r<
returnValue=false;
elseif(r<
*u2=r;
}
/*Thusp=0andlineisparalleltoclippingboundary.*/
if(q<
0.0)
/*Lineisoutsideclippingboundary.*/
return(returnValue);
voidlineClipLiangBarsk(wcPt2DwinMin,wcPt2DwinMax,wcPt2Dp1,wcPt2Dp2)
GLfloatu1=0.0,u2=1.0,dx=p2.getx()-p1.getx(),dy;
if(clipTest(-dx,p1.getx()-winMin.getx(),&
u1,&
u2))
if(clipTest(dx,winMax.getx()-p1.getx(),&
u2)){
dy=p2.gety()-p1.gety();
if(clipTest(-dy,p1.gety()-winMin.gety(),&
if(clipTest(dy,winMax.gety()-p1.gety(),&
if(u2<
1.0){
p2.setCoords(p1.getx()+u2*dx,p1.gety()+u2*dy);
}
if(u1>
p1.setCoords(p1.getx()+u1*dx,p1.gety()+u1*dy);
lineBres(round(p1.getx()),round(p1.gety()),
round(p2.getx()),round(p2.gety()));
}
再加上前面的框架代码,把其中的调用lineClipCohSuth改为lineClipLiangBarsk,注意参数的赋值。
三、上机练习
完整实现Cohen-Sutherland和梁友栋-Barskey线段裁减算法,理解裁减的基本原理,并继续体会怎样用键盘来控制图形的显示。