计算机图形学课程设计报告1.docx
- 文档编号:7381880
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:21
- 大小:121.38KB
计算机图形学课程设计报告1.docx
《计算机图形学课程设计报告1.docx》由会员分享,可在线阅读,更多相关《计算机图形学课程设计报告1.docx(21页珍藏版)》请在冰豆网上搜索。
计算机图形学课程设计报告1
[设计目的]
运用DDA算法画出斜率各不同的直线,包括大于-1小于1、等于1,大于1,小于-1,无穷大。
[设计思路](写出设计所参考的理论或算法步骤)
已知过端点P0(x0,y0),P1(x1,y1)的直线段L:
y=kx+b,直线斜率为
,
这种方法直观,但效率太低,因为每一步需要一次浮点乘法和一次舍入运算。
计算yi+1=kxi+1+b=kxi+b+kx=yi+kx
当x=1;yi+1=yi+k
●即:
当x每递增1,y递增k(即直线斜率);
●注意上述分析的算法仅适用于k≤1的情形。
在这种情况下,x每增加1,y最多增加1。
●当k1时,必须把x,y地位互换
[主要程序代码]
voidLineDDA(intx0,inty0,intx1,inty1,intcolor)
{
if(dx==0)
{x=x0;y=min(y0,y1);
while(y {putpixel((int)x,(int)y,color);y=y+1; delay(1000); } } else {m=dy/dx; if(fabs(m)<=1) {x=min(x0,x1); if(x==x0)y=y0;elsey=y1; for(;x<=max(x0,x1);x++) {putpixel((int)x,(int)(y+0.5),color); y+=m;delay(1000);} } else {y=min(y0,y1); if(y==y0) x=x0; elsex=x1; for(;y<=max(y0,y1);y++) {putpixel((int)(x+0.5),(int)y,color); x+=1/m;delay(1000); }}}} [运行效果](抓图及文字说明) [设计目的] 中点算法画直线的设计与实现 运用中点算法画出斜率各不同的直线,包括大于-1小于1、等于1,大于1,小于-1,无穷大。 [设计思路](写出设计所参考的理论或算法步骤) 中点画线算法的原则是: 如下图所示,但斜率K<1时,选定一个点之后,再计算中点M。 如果M>0,这线更靠近E点,下一点选择为E点。 反之选择NE点。 首先: f(x,y)=ax+by+c=0, 且 y=dy/dx*x+B, so: f(x,y)=dy*x-dx*y+Bdx=0 so: a=dy,b=-dx,c=Bdx. 假设,已经选定P点,应用中点法则选择下一点是,我们只要计算f(x+1,y+1/2),并考察是正数还是负数。 我们定义d=f(x+1,y+1/2)=a(x+1)+b(y+1/2)+c.这样,对于d>0,d<0,我们只要选择NE点和E点就可以了。 这边假设选定为E点,那么中点M的位置怎么变化和d的值如何变化呢? 显然M就沿着x轴递增一步。 此时: d1=f(x+2,y+1/2)从d1中减去d,可以得到一个增量差。 d1=a=dy。 同理: 如果选定下一点为NE点,d2=a+b=dy-dx。 基于上面的讨论,增量的中点技术可以概括为: 在每一步,我们根据上一步所得到的增量的符号去选择下一个像素点。 然后根据说选择的像素,判定变量增加相应的增量差d1或d2。 对于初始值,我们选择第一个端点为(x0,y0)。 则M为(x0+1,y+1/2).f(x0+1,y0+1/2)=f(x0,y0)+a+b/2. 故: d0=a+b/2=dy-dx/2 为去掉d0中的小数,我们对d0进行放大。 (在方程两边同乘于2) d0=2*dy–dxd1=2*dyd2=2*(dy-dx) [主要程序代码] voidMidPointLine(intx0,inty0,intx1,inty1,intcolor) { if(dx==0)/*k为无穷大*/ {y=min(y0,y1);x=x0; while(y {putpixel(x,y,color);delay(1000); y++; }} elseif(dy==0)/*k==0*/ {。 。 。 。 } else { k=(dy*1.0)/dx; if(k<1&&k>0)/*0 {x=min(x0,x1); if(x==x0) { y=y0; dy=-dy; } else{y=y1;dx=-dx;} d=dx+2*dy; incrE=+2*dy; incrNE=2*(dx+dy); putpixel(x,y,color); while(x {if(d>0) {x++; d+=incrE; } else {y++;x++;d+=incrNE; } putpixel(x,y,color);delay(1000); } } elseif(k>=1)/*whenk>1*/ {。 。 。 。 。 } elseif((k>=-1)&&(k<0))/*-1 {。 。 。 。 。 。 } else/*k<=-1*/ {。 。 。 。 。 。 。 。 。 } } } [运行效果](抓图及文字说明) [设计目的] Bresenham算法画直线的设计与实现 运用Bresenham算法画出斜率各不同的直线,包括大于-1小于1、等于1,大于1,小于-1,无穷大。 [设计思路](写出设计所参考的理论或算法步骤) 假定直线的起点、终点分别为: (x1,y1),(x2,y2),且都为整数。 则直线方程为y=mx+b,其中b=y1-mx1,m=dy/dx,当x每递增1,y递增k(即直线斜率) 取yi+1,yi由d1,d2的大小决定y=m(xi+1)+b, d1=y-yi,d2=yi+1–y, 当d1-d2>0, ; 当d1-d2<0, ; d1-d2=2y-2yi-1=2dy/dx(xi+1)+2b-2yi-1, dx(d1-d2)=2dy(xi+1)+2bdx-2yidx-dx, 设pi=dx(d1-d2),则pi=2xidy-2yidx+2dy+2bdx-dx (1) 则pi+1=2(xi+1)dy-2yi+1dx+2dy+2bdx-dx pi+1=2dy-2(yi+1-yi)dx+pi; 当pi>0时yi+1=yi+1,pi+1=2dy-2dx+pi 当pi<0时yi+1=yi,pi+1=2dy+pi 初值p1=2x1dy-2y1dx+2dy+2bdx-dx 因为y1dx=x1dy+bdx; 所以p1=2x1dy-2(x1dy+bdx)+2dy+2bdx-dx=2dy-dx 总结: p1=2dy-dxdx=x2-x1,dy=y2-y1 当p1>0时p2=p1+2dy-2dx 当p1<0时p2=p1+2dy,由此得出算法。 [主要程序代码] intBresenhamLine(intx0,inty0,intx1,inty1,intcolor) { d=0; if(dx==0) { y=min(y0,y1); x=x0; for(i=0;i { putpixel(x,y,color);delay(1000); y++; } return1; } if(dy==0) {。 。 。 。 。 。 } k=dy/dx; if(k<=1&&k>0)/*0 { x=min(x0,x1); if(x==x0) y=y0; else y=y1; for(i=0;i<=fabs(dx);i++) { d=d+k; if(d>=0.5) { y++; d=d-1; } x=x+1; putpixel(x,y,color);delay(1000); } } if(k>=1) {。 。 。 。 。 } if(k<=-1) {。 。 。 。 。 } if((k>=-1)&&(k<0)) {。 。 。 。 。 } [运行效果](抓图及文字说明 [设计目的] 中点算法画圆的设计与实现 运用中点算法,画出第一象限的四分之一圆弧,在运用其八对称性,画出其它象限的圆弧 [设计思路](写出设计所参考的理论或算法步骤) 利用圆的对称性,只须讨论1/8圆。 P为当前点亮象素,那么,下一个点亮的象素可能是P1(Xp+1,Yp)或P2(Xp+1,Yp-1)。 构造函数: F(X,Y)=X2+Y2-R2;则 F(X,Y)=0(X,Y)在圆上; F(X,Y)<0(X,Y)在圆内; F(X,Y)>0(X,Y)在圆外。 设M为P1、P2间的中点,M=(Xp+1,Yp-0.5),有如下结论: F(M)<0->M在圆内->取P1F(M)>=0->M在圆外->取P2 为此,可采用如下判别式: d=F(M)=F(xp+1,yp-0.5)=(xp+1)2+(yp-0.5)2-R2 若d<0,则P1为下一个象素,那么再下一个象素的判别式为: d1=F(xp+2,yp-0.5)=(xp+2)2+(yp-0.5)2-R2=d+2xp+3,即d的增量为2xp+3. 若d>=0,则P2为下一个象素,那么再下一个象素的判别式为: d1=F(xp+2,yp-1.=(xp+2)2+(yp-1.5)2-R2=d+(2xp+3)+(-2yp+2),即d的增量为2(xp-yp)+5.d的初值: d0=F(1,R-0.5)=1+(R-0.5)2-R2 =1.25-R [主要程序代码] voidMidpointCircle(intx0,inty0,intr,intcolor) { doubled=(5.0/4)-r; intx=0,y=r; while(x<=y) { putdot(x0,y0,x,y,color); if(d<0) d+=x*2.0+3; else {d+=2.0*(x-y)+5; y--;} x++; }} [运行效果](抓图及文字说明) [设计目的] 正负法算法画圆的设计与实现 运用正负法画出圆并掌握其方法 [设计思路](写出设计所参考的理论或算法步骤) 设圆的方程为F(x,y)=X2+Y2-R2=0; 假设求得Pi的坐标为(xi,yi); 则当Pi在圆内时->F(xi,yi)<0->向右->向圆外 Pi在圆外时->F(xi,yi)>0->向下->向圆内 即求得Pi点后选择下一个象素点Pi+1的规则为: 当F(xi,yi)≤0取xi+1=xi+1,yi+1=yi; 当F(xi,yi)>0取xi+1=xi,yi+1=yi-1; 这样用于表示圆弧的点均在圆弧附近,且使F(xi,yi)时正时负,故称正负法。 [主要程序代码] voidPNACircle(intx0,inty0,intr,intcolor) {x=0;y=r; putdot(x0,y0,x,y,color); x=1; putdot(x0,y0,x,y,color); d=1; while(y>=0) {if(d>=0) { d=d-2*y+1; y--; } else { d=d+2*x+1; x++; } putdot(x0,y0,x,y,color); } } [运行效果](抓图及文字说明) [设计目的] 中点算法画椭圆的设计与实现 运用类似中点算法画椭圆的方法画出椭圆 [设计思路](写出设计所参考的理论或算法步骤) 1,输入椭圆的两个半径r1和r2,并且输入椭圆的圆心。 设置初始点(x0,y0)的位置为(0,r2); 2,计算区域1中央决策参数的初始值p=ry*ry-rx*rx*ry+1/4*(rx*rx); 3,在区域1中的每个Xn为止,从n=0开始,直到|K|(斜率)小于-1时后结束; (1)如果p<0,绘制下一个点(x+1,y),并且计算p=p+r2*r2*(3+2*x); (2)如果P>=0,绘制下一个点(x+1,y-1),并且计算p=p+r2*r2*(3+2*point.x)-2*r1*r1*(y-1) 4,设置新的参数初始值;p=ry*ry(X0+1/2)*(X0+1/2)+rx*rx*(Y0-1)-rx*rx*ry*ry; 5,在区域2中的每个Yn为止,从n=0开始,直到y=0时结束。 (1)如果P>0的情况下,下一个目标点为(x,y-1),并且计算 p=p-2rx*rx*(Yn+1)+rx*rx; (2)如果p<=0的情况下,下一个目标点为(x+1,y-1),并且计算 p=p-2rx*rx*Y(n+1)+2ry*ry*(Xn+1)+rx*rx; 6,更具对称性原理计算其他3个象限的坐标。 7,急速拿出中心位置在(x1,y1)的位置x=x+x1; y=y+y1; [主要程序代码] voidMidpointEllipse(longx0,longy0,longa,longb,intcolor) { squarea=a*a; squareb=b*b; xP=(long)((float)squarea/(float)sqrt((float)(squarea+squareb))); yP=(long)((float)squareb/(float)sqrt((float)(squarea+squareb))); x=0; y=b; d=4*(squareb-squarea*b)+squarea; EllipsePoints(x0,y0,x,y,RED); while(x<=xP) {if(d<=0) d+=4*squareb*(2*x+3); else {d+=4*squareb*(2*x+3)+4*squarea*(2-2*y); y--; } x++; EllipsePoints(x0,y0,x,y,RED); } x=a; y=0; d=4*(squarea-a*squareb)+squareb; EllipsePoints(x0,y0,x,y,RED); while(y {if(d<=0) d+=4*squarea*(2*y+3); else {d+=4*squarea*(2*y+3)+4*squareb*(2-2*x); x--; } y++; EllipsePoints(x0,y0,x,y,RED); } } [运行效果](抓图及文字说明) [设计目的] 扫描转换矩形 确定那些像素位于填充图元的内部 确定以什么颜色填充这些像素 [设计思路](写出设计所参考的理论或算法步骤) 矩形确定边界,所以只要把矩形内部的点填充成所要的颜色即可 [主要程序代码] voidFillRectangle(intxmin,intxmax,intymin,intymax,intcolor) { intx,y; for(y=ymin;y<=ymax;y++) for(x=xmin;x<=xmax;x++) putpixel(x,y,color);delay(10000); } [运行效果](抓图及文字说明) [设计目的] 种子填充多边形 运用四连通图形,选定图形内部一点(种子),填充多边形 [设计思路](写出设计所参考的理论或算法步骤) 设G为一内点表示的区域,(x,y)为区域内一点,old_color为G的原色。 现取(x,y)为种子点对区域G进行填充: 即先置像素(x,y)的颜色为new_color,然后逐步将整个区域G都置为同样的颜色。 步骤如下: –种子象素入栈,当栈非空时,执行如下三步操作: •栈顶象素出栈; •将出栈象素置成多边形色; 按上、下、左、右的顺序检查与出栈象素相邻的四个象素,若其中某个象素不在边界上且未置成多边形色,则把该象素入栈。 [主要程序代码] voidscanlinefill4(intx,inty,intoldcolor,intnewcolor) { intxLeft,xRight,i; intisleftendset,spanneedfill; Spanspan; linkstack*s=(linkstack*)malloc(sizeof(linkstack)); s->top=NULL; i=x; while(getpixel(i,y)==oldcolor) { putpixel(i,y,newcolor); i++; } span.xRight=i-1; i=x-1; while(getpixel(i,y)==oldcolor) { putpixel(i,y,newcolor); i--; } span.xLeft=i+1;/*确定区段左边界*/ setstackempty(s);/*初始化*/ span.y=y; pushstack(s,&span);/*将前面生成的区段压入堆栈*/ while(! isstackempty(s)) { popstack(s,&span); y=span.y+1;/*处理上面扫描线*/ xRight=span.xRight; i=span.xLeft-1; isleftendset=false; while(getpixel(i,y)==oldcolor)/*向左填充*/ { putpixel(i,y,newcolor); i--; } if(i! =span.xLeft-1)/*确定区段左边界*/ { isleftendset=true; xLeft=i+1; } i=span.xLeft; while(i { spanneedfill=false; while(getpixel(i,y)==oldcolor)/*向右填充*/ { if(! spanneedfill) { spanneedfill=true; if(! isleftendset) { isleftendset=true; xLeft=i; } } putpixel(i,y,newcolor); i++; } if(spanneedfill) { span.y=y; span.xLeft=xLeft; span.xRight=i-1; pushstack(s,&span);/*将区段压入堆栈*/ isleftendset=false; spanneedfill=false; } while(getpixel(i,y)! =oldcolor) i++; } y=y-2;/*处理下面一条扫描线,与处理上面一条扫描线完全类似*/ xRight=span.xRight; i=span.xLeft-1; isleftendset=false; while(getpixel(i,y)==oldcolor)/*向左填充*/ { putpixel(i,y,newcolor); i--; } if(i! =span.xLeft-1)/*确定区段左边界*/ { isleftendset=true; xLeft=i+1; } i=span.xLeft; while(i { spanneedfill=false; while(getpixel(i,y)==oldcolor)/*向右填充*/ { if(! spanneedfill) { spanneedfill=true; if(! isleftendset) { isleftendset=true; xLeft=i; } } putpixel(i,y,newcolor); i++; } if(spanneedfill) {span.y=y; span.xLeft=xLeft; span.xRight=i-1; pushstack(s,&span);/*将区段压入堆栈*/ isleftendset=false; spanneedfill=false; }while(getpixel(i,y)! =oldcolor) i++; }delay(1000); } } [运行效果](抓图及文字说明) [设计目的] 线段裁剪 运用Cohen-Sutherland算法裁剪 [设计思路](写出设计所参考的理论或算法步骤) (1)输入直线段的两端点坐标: p1(x1,y1)、p2(x2,y2),以及窗口的四条边界坐标: wyt、wyb、wxl和wxr。 (2)对p1、p2进行编码: 点p1的编码为code1,点p2的编码为code2。 (3)若code1==0且code2==0,对直线段应简取之,转(6);否则,若code1&code2≠0,对直线段可简弃之,转(7);当上述两条均不满足时,进行步骤(4)。 (4)确保p1在窗口外部: 若p1在窗口内,则交换p1和p2的坐标值和编码。 (5)按左、右、上、下的顺序求出直线段与窗口边界的交点,并用该交点的坐标值替换p1的坐标值。 也即在交点s处把线段一分为二,并去掉p1s这一段。 考虑到p1是窗口外的一点,因此可以去掉p1s。 转 (2)。 (6)用直线扫描转换算法画出当前的直线段p1p2。 (7)算法结束。 [主要程序代码] voidCohenSutherlandLineClip(floatx0,floaty0,floatx1,floaty1,Rectangle*rect) /*P0(x0,y0)P1(x1,y1)为待裁剪直线段*/ /*rect为裁剪窗口*/ {voidCompOutCode
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 图形学 课程设计 报告