计算机图形学实验报告 课程设计 大作业.docx
《计算机图形学实验报告 课程设计 大作业.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验报告 课程设计 大作业.docx(22页珍藏版)》请在冰豆网上搜索。
计算机图形学实验报告课程设计大作业
安徽建筑工业学院
计算机图形学实验报告
院(系)名称:
专业:
班级:
姓名:
学号:
指导老师:
实验一实现任意直线的中点画线算法
【实验目的】
掌握直线的中点画线算法;
【实验环境】
VC++6.0
【实验内容】
利用任意的一个实验环境,编制源程序,实现直线的中点画线法。
【实验原理】
假定直线斜率k在0~1之间,当前象素点为(xp,yp),则下一个象素点有两种可选择点P1(xp+1,yp)或P2(xp+1,yp+1)。
若P1与P2的中点(xp+1,yp+0.5)称为M,Q为理想直线与x=xp+1垂线的交点。
当M在Q的下方时,则取P2应为下一个象素点;当M在Q的上方时,则取P1为下一个象素点。
这就是中点画线法的基本原理。
图2.1.2中点画线法每步迭代涉及的象素和中点示意图
下面讨论中点画线法的实现。
过点(x0,y0)、(x1,y1)的直线段L的方程式为F(x,y)=ax+by+c=0,其中,a=y0-y1,b=x1-x0,c=x0y1-x1y0,欲判断中点M在Q点的上方还是下方,只要把M代入F(x,y),并判断它的符号即可。
为此,我们构造判别式:
d=F(M)=F(xp+1,yp+0.5)=a(xp+1)+b(yp+0.5)+c
当d<0时,M在L(Q点)下方,取P2为下一个象素;
当d>0时,M在L(Q点)上方,取P1为下一个象素;
当d=0时,选P1或P2均可,约定取P1为下一个象素;
注意到d是xp,yp的线性函数,可采用增量计算,提高运算效率。
若当前象素处于d≥0情况,则取正右方象素P1(xp+1,yp),要判下一个象素位置,应计算d1=F(xp+2,yp+0.5)=a(xp+2)+b(yp+0.5)=d+a,增量为a。
若d<0时,则取右上方象素P2(xp+1,yp+1)。
要判断再下一象素,则要计算d2=F(xp+2,yp+1.5)=a(xp+2)+b(yp+1.5)+c=d+a+b,增量为a+b。
画线从(x0,y0)开始,d的初值d0=F(x0+1,y0+0.5)=F(x0,y0)+a+0.5b,因 F(x0,y0)=0,所以d0=a+0.5b。
由于我们使用的只是d的符号,而且d的增量都是整数,只是初始值包含小数。
因此,我们可以用2d代替d来摆脱小数,写出仅包含整数运算的算法程序。
【实验程序】
voidMidpointLine(intx0,inty0,intx1,inty1,intcolor)
{inta,b,d1,d2,d,x,y;
a=y0-y1;b=x1-x0;d=2*a+b;
d1=2*a;d2=2*(a+b);
x=x0;y=y0;
drawpixel(x,y,color);
while(x {if(d<0) {x++;y++;d+=d2;}
else {x++;d+=d1;}
drawpixel(x,y,color);
}/*while*/
}/*midPointLine*/
举例:
用中点画线方法扫描转换连接两点P0(0,0)和P1(5,2)的直线段。
a=y0-y1=-2;b=x1-x0=5;d0=2*a+b=1;d1=2*a=-4;d2=2*(a+b)=6,
xy d
00 1
10 -3
21 3
31 -1
42 5
52 15 2.1.3中点画线法
实验二实现任意一种线段的裁剪算法以及多边形裁剪算法
【实验目的】
1、掌握直线段裁剪的基本原理;
2、掌握多边形裁剪的基本原理;
【实验环境】
VC++6.0
【实验内容】
编制程序,完成直线段和多边形的裁减过程。
【实验原理】
1.算法基本思想
对每条直线段p1(x1,y1)p2(x2,y2)分三种情况处理:
(1)直线段完全可见,“简取”之。
(2)直线段完全不可见,“简弃”之。
(3)直线段既不满足“简取”的条件,也不满足“简弃”的条件,需要对直线段按交点进行分段,分段后重复上述处理。
2.算法步骤
(1)编码
对于任一端点(x,y),赋予一个4位的二进制码D3D2D1D0。
编码规则如下:
若x若x>wxr,则D1=1,否则D1=0;
若y若y>wyt,则D3=1,否则D3=0。
(2)裁剪
先求出端点p1和p2的编码code1和code2,然后:
若code1|code2=0,对直线段应简取之。
若code1&code2≠0,对直线段可简弃之。
若上述两条件均不成立。
则需求出直线段与窗口边界的交点。
在交点处把线段一分为二,其中必有一段完全在窗口外,可以弃之。
再对另一段重复进行上述处理,直到该线段完全被舍弃或者找到位于窗口内的一段线段为止。
(3)求交
假定直线的端点坐标为(x1,y1)和(x2,y2)左、右边界交点的计算上、下边界交点的计算。
3.算法实现
(1)输入直线段的两端点坐标:
p1(x1,y1)、p2(x2,y2),以及窗口的四条边界坐标:
wyt、wyb、wxl和wxr。
(2)对p1、p2进行编码:
点p1的编码为code1,点p2的编码为code2。
(3)若code1|code2=0,对直线段应简取之,转(6);否则,若code1&code2≠0,对直线段可简弃之,转(7);当上述两条均不满足时,进行步骤(4)。
(4)确保p1在窗口外部:
若p1在窗口内,则交换p1和p2的坐标值和编码。
(5)按左、右、上、下的顺序求出直线段与窗口边界的交点,并用该交点的坐标值替换p1的坐标值。
也即在交点s处把线段一分为二,并去掉p1s这一段。
考虑到p1是窗口外的一点,因此可以去掉p1s。
转
(2)。
(6)用直线扫描转换算法画出当前的直线段p1p2。
(7)算法结束。
【实验程序】
一:
Cohen-Sutherland线段裁剪算法
#include
//#include/*SetPixel()*/
#include
#include
///////////////////////////////////////////////////////////////////////////
constwinLeftBitCode=0x1;
constwinRightBitCode=0x2;
constwinBottomBitCode=0x4;
constwinTopBitCode=0x8;
///////////////////////////////////////////////////////////////////////////
classwcPt2D{public:
GLfloatx,y;};
///////////////////////////////////////////////////////////////////////////
inlineintinside(intcode){returnint(!
code);}
//////////////////////////////////////////////////////////////////////////
inlineintreject(intcode1,intcode2)
{
returnint(code1&code2);
}
/////////////////////////////////////////////////////////////////////////
inlineintaccept(intcode1,intcode2)
{
returnint(!
(code1|code2));
}
/////////////////////////////////////////////////////////////////////////
GLubyteencode(wcPt2Dpt,wcPt2DwinMin,wcPt2DwinMax)
{
GLubytecode=0x00;
if(pt.xcode=code|winLeftBitCode;
if(pt.x>winMax.x)
code=code+winRightBitCode;
if(pt.ycode=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;
}
////////////////////////////////////////////////////////////////////////
voiddraw_pixel(intix,intiy/*,intvalue*/)
{
glBegin(GL_POINTS);
glVertex2i(ix,iy);
glEnd();
}
////////////////////////////////////////////////////////////////////////
intinlineround(constfloata){returnint(a+0.5);}
/////////////////////////////////////////////////////////////////////////
voidlineDDA(intx0,inty0,intx_end,inty_end,doublea,doubleb,doublec)
{
glColor3f(a,b,c);
intdx=x_end-x0;
intdy=y_end-y0;
intsteps,k;
floatxIncrement,yIncrement,x=x0,y=y0;
if(abs(dx)>abs(dy))
steps=abs(dx);
else
steps=abs(dy);
xIncrement=float(dx)/float(steps);
yIncrement=float(dy)/float(steps);
draw_pixel(round(x),round(y));
for(k=0;k{
x+=xIncrement;
y+=yIncrement;
draw_pixel(round(x),round(y));
}
}
////////////////////////////////////////////////////////////////////////////////////
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))
done=true;
else
{
if(inside(code1))
{
swapPts(&p1,&p2);
swapCodes(&code1,&code2);
}
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;
}
else
if(code1&winRightBitCode)
{
p1.y+=(winMax.x-p1.x)*m;
p1.x=winMax.x;
}
else
if(code1&winBottomBitCode)
{
if(p2.x!
=p1.x)
p1.x+=(winMin.y-p1.y)/m;
p1.y=winMin.y;
}
else
if(code1&winTopBitCode)
{
if(p2.x!
=p1.x)
p1.x+=(winMax.y-p1.y)/m;
p1.y=winMax.y;
}
}
}
if(plotLine)
lineDDA(round(p1.x),round(p1.y),round(p2.x),round(p2.y),0.0,0.0,1.0);
}
///////////////////////////////////////////////////////////////////////////////////////
voiddisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
wcPt2DwinMin,winMax,p1,p2,q1,q2,t1,t2,m1,m2;
//裁剪窗口
winMin.x=80;
winMin.y=100;
winMax.x=290;
winMax.y=500;
/*lineDDA(80,100,80,450,1.0,0.0,0.0);
lineDDA(80,100,290,100,1.0,0.0,0.0);
lineDDA(290,100,290,450,1.0,0.0,0.0);
lineDDA(80,450,290,450,1.0,0.0,0.0);
*/
/*//全图
winMin.x=0;
winMin.y=000;
winMax.x=500;
winMax.y=500;
*/
///////////////////////
p1.x=0;
p1.y=0;
p2.x=400;
p2.y=400;
//////////////////////
q1.x=0;
q1.y=0;
q2.x=100;
q2.y=400;
//////////////////////
t1.x=100;
t1.y=400;
t2.x=400;
t2.y=400;
//////////////////////
m1.x=300;
m1.y=200;
m2.x=100;
m2.y=400;
//只显示裁剪框内的线段
lineClipCohSuth(winMin,winMax,p1,p2);
lineClipCohSuth(winMin,winMax,q1,q2);
lineClipCohSuth(winMin,winMax,t1,t2);
lineClipCohSuth(winMin,winMax,m1,m2);
//显示裁剪框和待剪线段
/*
lineDDA(300,200,100,400,0.0,0.0,1.0);
lineDDA(0,0,100,400,0.0,0.0,1.0);
lineDDA(100,400,400,400,0.0,0.0,1.0);
lineDDA(0,0,400,400,0.0,0.0,1.0);
*/
glFlush();
}
voidmyinit()
{
glClearColor(0.8,1.0,1.0,1.0);
//glColor3f(0.0,0.0,1.0);
glPointSize(1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,500.0,0.0,500.0);
glViewport(0,0,200,500);
}
voidmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(200.0,200.0);
glutCreateWindow("CG_test_CG_test_Cohen-Sutherland线段裁剪算法示例");
//glutFullScreen();
glutDisplayFunc(display);
myinit();
glutMainLoop();
}
稍微修改源程序即可得到以下裁剪框以及被裁剪线段:
二:
Sutherland_Hodgman多边形裁剪算法
#defineTRUE1
#defineFALSE0
typedefstruct{
floatx,y;
}vertex;
voidintersect(p1,p2,clipboundary,intersectp)
vertexp1,p2,*clipboundary,*intersectpt;
/*p1和p2为多边形的边的起点和终点,clipboundary为窗口边界,intersectpt中返回边与窗口边界的交点*/
{
if(clipboundary[0].y==clipboundary[1].y)/*水平边界*/
{
intersectpt->y=clipboundary[0].y;
intersectpt->x=p1.x+(clipboundary[0].y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y);
}
else/*垂直边界*/
{
intersectpt->x=clipboundary[0].x;
intersectpt->y=p1.y+(clipboundary[0].x-p1.x)*(p2.y-p1.y)/(p2.x-p1.x);
}
}
intinside(testvertex,clipboundary)
vertextestvertex,*clipboundary;
/*如果顶点testvertex在窗口边界clipboundary的内部,那么返回TRUE;否则返回FALSE*/
{
if(clipboundary[1].xif(testvertex.y<=clipboundary[0].y)
returnTRUE;
if(clipboundary[1].x>clipboundary[0].x)/*下边界*/
if(testvertex.y>=clipboundary[0].y)
returnTRUE;
if(clipboundary[1].y>clipboundary[0].y)/*右边界*/
if(testvertex.x<=clipboundary[0].x)
returnTRUE;
if(clipboundary[1].yif(testvertex.y<=clipboundary[0].x)
returnTRUE;
returnFALSE;
}
outputvertex(outvertex,outlength,outvertexlist)
vertexoutvertex;
int*outlength;
vertex*outvertexlist
/*向输出顶点序列中输出顶点outvertex*/
{
outvertexlist[*outlength]=outvertex;
(*outlength)++;
}
voidSutherland_Hodgman_Polygon_Clipping(invertexlist,outvertexlist,inlength,outlength,clipboundary)
vertex*invertexlist,*outvertexlist;
intinlength,*outlength;
vertex*clipboundary;
/*invertexlist为输入顶点序列,inlength为输入序列长度;outvertexlist为输出顶点序列,outlenght中返回输出序列长度;clipboundary为窗口边界*/
{
vertexs,p,i;
intj;
*outlength=0;
s=invertexlist[inlength-1];/*输入顶点序列的最后一个顶点*/
for(j=0;j{
p=invertexlist[j];
if(inside(p,clip