计算机图形学实验报告
一、 实验题目:
利用计算机编程语言绘制图形,主要实现以下内容: (1)、中点算法生成任意斜率直线,并设置线型线宽。 (2)、中点算法生成圆 (3)、中点算法生成椭圆
(4)、扫描算法实现任意多边形填充 (5)、Cohen_Sutherland裁剪 (6)、自由曲线与曲面的绘制 (7)、二维图形变换 (8)、三视图变换
二、系统分析与设计
本实验采用C语言编程,运行环境为TurboC;
三、算法思想及程序实现
1、中点算法生成任意斜率直线,并设置线型线宽。
(1).算法思想
假定直线斜率k在0~1之间(k的其它取值可以类似处理),当前象素点为(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为下一个象素点。这就是中点画线法的基本原理。
下面讨论中点画线法的实现。过点(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的线性函数,可采用增量计算,提高运算效率。
1
计算机图形学实验报告 计算机072 070814082周蔓
若当前象素处于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来摆脱小数。 (2)程序实现
void putpixels(int x,int y,int color,int n) { int i,j;
for(i=-n/2;i<=n/2;i++) for(j=-n/2;j<=n/2;j++) putpixel(x+j,y+i,color); }
void Midpointline(int x0,int y0,int x1,int y1,int color,int n) {
int a,b,dx,dy,d,x,y,incrP1,incrP2; if(x0==x1)
{
if(y0 for(y=y0;y>=y1;y--) putpixel(x0,y,color); } else if(x0 d = dx-2*dy; 2 计算机图形学实验报告 计算机072 070814082周蔓 incrP1 = -2*dy; incrP2 = 2*(dx-dy); x = x0; y = y0; putpixels(x,y,color,n); while (x {y++; d +=incrP2;} if (d<0) else d +=incrP1; x++; putpixels(x,y,color,n); } } else { dy = y1-y0; dx = x1-x0; d=-2*dy-dx; incrP1 = -2*(dx+dy); incrP2 = -2*dy; x = x0; y = y0; putpixels(x,y,color,n); while(x { y--;d +=incrP1;} else d +=incrP2; x++; putpixels(x,y,color,n); } } } else if(x0>x1) { if(y0 计算机图形学实验报告 计算机072 070814082周蔓 { dy = y0-y1; dx = x0-x1; d=-2*dy-dx; incrP1 = -2*(dx+dy); incrP2 = -2*dy; x = x1; y = y1; putpixels(x,y,color,n); while (x { y--;d +=incrP1;} else d +=incrP2; x++; putpixels(x,y,color,n); } } else { dy = y0-y1; dx = x0-x1; d = dx-2*dy; incrP1 = -2*dy; incrP2 = 2*(dx-dy); x = x1; y = y1; putpixels(x,y,color,n); while (x {y++; d +=incrP2;} else if (d<0) d +=incrP1; x++; putpixels(x,y,color,n); } } }} 4 计算机图形学实验报告 计算机072 070814082周蔓 2、用中点算法实现画圆 (1). 算法思想 如果我们构造函数 F(x,y)=x2+y2-R2,则对于圆上的点有F(x,y)=0,对于圆外的点有F(x,y)>0,对于圆内的点F(x,y)<0 。与中点画线法一样,构造判别式: d=F(M)=F(xp+1,yp-0.5)=(xp+1)2+(yp-0.5)2-R2 若 d<0,则应取P1为下一象素,而且再下一象素的判别式为: d=F(xp+2,yp-0.5)=(xp+2)2+(yp-0.5)2-R2=d+2xp+3 若d≥0,则应取P2为下一象素,而且下一象素的判别式为 d=F(xp+2,yp-1.5)=(xp+2)2+(yp-1.5)2-R2=d+2(xp-yp)+5 我们这里讨论的第一个象素是(0,R),判别式d的初始值为: d0=F(1,R-0.5)=1.25-R 为了进一步提高算法的效率,将上面的算法中的浮点数改写成整数,将乘法运算改成加法运算,即仅用整数实现中点画圆法。 (2)程序实现: void midpointcircle(int R) { int x,y,deltax,deltay,d; x=0;y=R;d=1-R; deltax=3; deltay=5-R-R; putpixel(x+300,y+300,GREEN); while(x d+=deltax; deltax+=2; x++; } else { d+=deltax+deltay; deltax+=2; deltay+=2; 5 计算机图形学实验报告 计算机072 070814082周蔓 x++; y--; } putpixel(x+300,y+300,RED); putpixel(y+300,x+300,GREEN); putpixel(-x+300,y+300,BLUE); putpixel(y+300,-x+300,WHITE); putpixel(x+300,-y+300,YELLOW); putpixel(-y+300,x+300,CYAN); putpixel(-x+300,-y+300,MAGENTA); putpixel(-y+300,-x+300,BROWN); } } 3、用中点算法实现椭圆: (1)、算法思想 生成椭圆弧的中点算法和直线的中点算法类似,只是初始化条件和判别式的递推公式不同,并且在确定判别式的时候要消去浮点运算和尽量减少乘法的次数,对于椭圆,还要注意,在第一像限内斜率大于1的情况与直线|m|>1时相同,要以y为自变量,在此不再详细叙述。对于椭圆:考虑分界点的上部的弧段,此段的斜率m[1,0],由像素(xi,yi)递推出后继的像素(xi1,yi1,r)。根据条件得到 1131yi[yi,r,yi,r)yi1[yi,r,yi,r) 2222yi1,ryi,r 当di0 y1 当d0ii,r2di4b(2xi3) 当di0di1 22di4b(2xi3)8a(yi,r1) 当di0 6 计算机图形学实验报告 计算机072 070814082周蔓 (x0,y0,r)(0,b)初始条件为d04F(1,b1)4b24a2ba2,对于分界点下方的弧段,可类似 2{求得。 (2)程序实现 void putpixels(int x,int y,int color,int n) { int i,j; for(i=-n/2;i<=n/2;i++) for(j=-n/2;j<=n/2;j++) putpixel(x+j,y+i,color); } void ellipsepoint(long x0,long y0,long x,long y,long color,int n) { putpixels((int)(x0+x),(int)(y0+y),(int)color,n); putpixels((int)(x0-x),(int)(y0+y),(int)color,n); putpixels((int)(x0+x),(int)(y0-y),(int)color,n); putpixels((int)(x0-x),(int)(y0-y),(int)color,n); } void midpointellipse(long x0,long y0,long a,long b,long color,int n) { long x,y,d,sa,sb,xp,yp; sa=a*a,sb=b*b; xp=(long)((float)sa/(float)sqrt((float)(sa+sb))); yp=(long)((float)sb/(float)sqrt((float)(sa+sb))); x=0,y=b,d=sa+4*sb-4*sa*b; while(x 7 计算机图形学实验报告 计算机072 070814082周蔓 } else { d=d+4*sb*(2*x+3)+4*sa*(2-2*y); x++; y--; } ellipsepoint(x0,y0,x,y,color,n); } x=a,y=0,d=4*sa+sb-4*a*sb; while(y d=d+4*sa*(2*y+3)+4*sb*(2-2*x); y++; x--; } ellipsepoint(x0,y0,x,y,color,n); } } 8 计算机图形学实验报告 计算机072 070814082周蔓 4、用扫描线算法实现多边形填充: (1)算法思想: 用水平扫描线从上到下扫描由点线段构成的多段定义的多边形。每根扫描线与多边形各边产生一系列交点,将这些交点按照x坐标进行排序,将排序后的交点成对取出,作为两个端点,用所需填充的色彩画水平直线。多边形被扫描完毕,则填充结束。 实现步骤: (1) 建立边的分类表ET; (2) 将扫描线纵坐标y的初值为ET中非空元素的最小序号; (3) 置活化边表AEL为空; (4) 执行下列步骤直至ET和AEL都为空; A、如果ET中的第y类非空,则将其中的所有边取出并插入AEL中,在插 入过程忠进行排序; B、 对AEL中的边两两配对,将每对边中x坐标按规则取整,获得有效 的填充区段,再填充; C、 将当前扫描线纵坐标y值递增1,即y=1; D、将AEL中满足y=ymax边删去; E、对AEL中剩下的每一条边的x递增deltax,即x=x+deltax; (2)程序实现 typedef struct { int y_top; float x_int; int delta_y; float x_change_per_scan; }EACH_ENTRY; EACH_ENTRY sides[MAX_POINT]; int x[MAX_POINT],y[MAX_POINT]; int side_count,first_s,last_s,scan,bottomscan,x_int_count; void fill_area(int count) { sort_on_bigger_y(count); first_s=1; last_s=1; for(scan=sides[1].y_top;scan>=bottomscan;scan--) { update_first_and_last(count,scan); process_x_intersections(first_s,last_s); 9 计算机图形学实验报告 计算机072 070814082周蔓 draw_lines(scan,x_int_count,first_s); update_sides_list(); } } sort_on_bigger_y(int n) { int k,x1,y1;int tem; side_count=0; y1=y[n]; x1=x[n]; bottomscan=y[n]; for(k=1;k put_in_sides_list(side_count,x1,y1,x[k],y[k],tem); } else { setcolor(13); line(x1,y1,x[k],y[k]); } if(y[k] while((entry>1)&&(maxy>sides[entry-1].y_top)) { sides[entry]=sides[entry-1]; entry--; } sides[entry].y_top=maxy; sides[entry].delta_y=abs(y2-y1)+1; if(y1>y2) sides[entry].x_int=x1; else sides[entry].x_int=x2_temp; sides[entry].x_change_per_scan=x_change_temp; } update_first_and_last(int count,int scan) 10 计算机图形学实验报告 计算机072 070814082周蔓 { while((sides[last_s+1].y_top>=scan)&&(last_s sort_on_x(int entry,int first_s) { while((entry>first_s)&&(sides[entry].x_int x->x_int=y->x_int;y->x_int=f_temp; i_temp=x->delta_y;x->delta_y=y->delta_y; y->delta_y=i_temp; f_temp=x->x_change_per_scan; x->x_change_per_scan=y->x_change_per_scan; y->x_change_per_scan=f_temp; } draw_lines(int scan,int x_int_count,int index) { 11 计算机图形学实验报告 计算机072 070814082周蔓 int k,x,x1,x2; for(k=1;k<(int)(x_int_count/2+1.5);k++) { while(sides[index].delta_y==0) index++; x1=(int)(sides[index].x_int+0.5); index++; while(sides[index].delta_y==0) index++; x2=(int)(sides[index].x_int+0.5); setcolor(13); line(x1,scan,x2,scan); index++; } } update_sides_list() { int k; int temp; for(k=first_s;k sides[k].x_int-=sides[k].x_change_per_scan; } } } 12 计算机图形学实验报告 计算机072 070814082周蔓 5、用Cohen-Sutherland裁剪算法实现直线段裁剪: 5.1编码算法: 5.1.1算法思想: 本算法分为三个步骤:判断线段两端是否都在窗口内,如果是,线段完全可见;否则判断线段是否显然不可见,如果是,裁剪结束。否则求线段与窗口边延长线的交点,此线段将线段分为两段,其中一段不可见,舍弃。对余下的线段继续进行递归裁剪。算法的编码是进行二进制位运算,若顶点在窗口内,则二进制编码为0000;否则进行编码。 5.1.2实现步骤: (1)这种算法利用编码的方法,延长窗口边线,使得它们把包含未经裁剪图形的窗口平面区域分成九个区域: (2)每个区域用一个4位编码CtCbCrCl来表示,代码中每一位分别是0或1,是按照窗口边线来确定的,下面给出具体的编码规则,其中最右边的位Cl是第一位,依次Cr第二、Cb第三、Ct第四位。 A、当两端点P1(x1,y1)和P2(x2,y2)在区域0000中,即满足点的裁剪不 等式: B、当两个端点在窗口边线外的同侧位置,则他们的四位代码中,有一相同位,同时位“1”,显然两个端点代码C1和C2按位与运算 C1&C2≠0 .由此可检查判断直线在窗口外,应全部舍弃。 C、果直线两端点不满足上述两种情况,不能简单地全部保留或全部舍弃直线时,则需要计算出直线与窗口边线的交点,将直线分段后继续进行检查判断。这样可以逐段地舍弃位于窗口外地线段,保留剩余在窗口内的线段。 5.1.3程序实现 /*********定义裁剪函数************/ void line_clip(int x1, int y1, int x2, int y2, int left,int top,int right, int bottom) { void getcode(int x,int y,int d[4]); /*定义获得端点的代码函数*/ int i,x11,y11; /*定义交点坐标*/ int aa=1; getcode(x1,y1,a); getcode(x2,y2,b); /*1:裁剪循环开始*/ while(aa!=0) 13 计算机图形学实验报告 计算机072 070814082周蔓 { if((a[0]+a[1]+a[2]+a[3]==0)&&(b[0]+b[1]+b[2]+b[3]==0)) /*第一种情况线段完全可见*/ { aa=0; return; } else if((a[0]&&b[0])+(a[1]&&b[1])+(a[2]&&b[2])+(a[3]&&b[3])!=0) /*线段完全不可见*/ { setcolor(0); setwritemode(0); /*设置画线的输出模式为覆盖方式*/ line(x1,y1,x2,y2); /*进行裁剪 也就是进行覆盖*/ aa=0; return; } /*2:线段即不完全可见,也不完全不可见,即与边有交点的线段的裁剪处理*/ else { if(a[0]+a[1]+a[2]+a[3]==0) /*寻找不可见点*/ { for(i=0;i<4;i++) c[i]=b[i];/*x2,y2为不可见点*/ } else { for(i=0;i<4;i++) c[i]=a[i];/*x1,y1为不可见点*/ } /*3:直线与窗口边作求交运算,求出交点赋值给x11、y11*/ if(c[0]==1) { x11=left; 14 计算机图形学实验报告 计算机072 070814082周蔓 y11=(int)((y2-y1)*(left-x1)/(x2-x1)+y1); } else if(c[1]==1) { x11=right; y11=(int)((y2-y1)*(right-x1)/(x2-x1)+y1); } else if(c[2]==1) { x11=(int)((x2-x1)*(bottom-y1)/(y2-y1)+x1); y11=bottom; } else if(c[3]==1) { x11=(int)((x2-x1)*(top-y1)/(y2-y1)+x1); y11=top; } /*3:求交运算结束*/ if((c[0]==a[0])&&(c[1]==a[1])&&(c[2]==a[2])&&(c[3]==a[3])) { setcolor(0); setlinestyle(0,0,3); setwritemode(0); line(x1,y1,x11,y11); x1=x11; y1=y11; getcode(x11,y11,a); } else if((c[0]==b[0])&&(c[1]==b[1])&&(c[2]==b[2])&&(c[3]==b[3])) { setcolor(0); setlinestyle(0,0,3); setwritemode(0); line(x2,y2,x11,y11); x2=x11;y2=y11; getcode(x11,y11,b); 15 计算机图形学实验报告 计算机072 070814082周蔓 } } /*2:与边有交点的线段裁剪处理结束*/ } /*1:裁剪循环结束*/ } /*获得端点代码*/ void getcode(int x,int y,int d[4]) { d[0]=0;d[1]=0;d[2]=0;d[3]=0; if(x 计算机图形学实验报告 计算机072 070814082周蔓 6、自由曲线与曲面的绘制 6.1、生成Bezier曲线 (1)算法思想 利用Bezier曲线造型时,如果其次数太高,固然能表示复杂的形状,但同时造成计算复杂度增加,而二次Bezier曲线表示能力有限,故下面我们仅讨论三次Bezier曲线的矩阵表示和计算机生成。 (1) 矩阵表示 三次Bezier曲线的定义式为: P(t)PBii,3(t), t[0,1] i03将其分解为两个矢量的点积为: B0,3(t)B(t)1,3 P(t)[P0,P,P,P]123B(t)2,3B3,3(t)取Bezier曲线的几何矩阵GB[P0,P1,P2,P3],则有: C30(1t)312C(1t)3P(t)GB2GB1C3(1t)33C3t13t3t2t3233t6t3tGB3t23t33t1 -3 3 -10 3 -6 30 0 3 -30 0 0 11tGMT BBt23t得到三次Bezier曲线的基矩阵为: 1 -3 3 -10 3 -6 3 MB0 0 3 -30 0 0 1(2) 三次Bezier曲线的生成 Bezier曲线P(t)用的参数表示法,因此将区间[0,1]分成N等份,确定了控制点后,每取一个ti都对应一个三维的点Di(xi,yi,zi)。这样,在每两个Di和Di1之间画一条直线,再将该这些直线段投影到二维平面,就可以得到我们需要的Bezier曲线了。 (2)程序实现: void bezier_3(int color, double p[4][2]) { 17 计算机图形学实验报告 计算机072 070814082周蔓 double t,t1,t2,xt,yt; int rate=200,x,y; setcolor(color); moveto(p[0][0],p[0][1]); for (t=0;t<=1;t+=1.0/rate) { yt=1-t; t1=yt*yt; t2=3*yt*t; xt=p[0][0]*t1*yt+p[1][0]*t2*yt+p[2][0]*t2*t+p[3][0]*t*t*t; yt=p[0][1]*yt*t1+p[1][1]*t2*yt+p[2][1]*t2*t+p[3][1]*t*t*t; x=(int)(xt); y=(int)(yt); lineto(x,y); } } 6.2绘制Bezier曲面 (1)算法思想: Bezier曲线是一条与控制多边形顶点位置有严格关系的曲线, Bezier曲线形状趋向于特征多边形的形状,而且阶数由控制多边形顶点的个数决定。Bezier曲面则是由Bezier曲线拓广而来,它也是以Bernstein函数作为基函数,是由Bernstein基函数构造空间点阵列的位置来控制的。 (2)算法实现步骤: 1.给出控制顶点。 2.根据如下公式,编程绘制Bezier曲面。 33P(u,v)PBiji0j0i,3(u)Bj,3(v)v2(0u,v1)v1]TP01P11P21P31P01P12P22P32P01P13P23P33[u3u23u33001]NPNT[v310NT0018 1 3N 3 1 TTUNPNV 630P00PP10P20P30 计算机图形学实验报告 计算机072 070814082周蔓 计算各点坐标 3. 用画直线的方法首尾相接的画直线。 (3)、程序实现: main() { char str[80]; int driver,mode; int i,k,m,j; int x0=300,y0=300; int p[4][4][3]={{{12,145,50},{24,120,50},{45,117,50},{65,140,50}}, {{24,65,34},{56,45,34},{87,56,34},{99,75,34}}, {{43,120,20},{65,98,20},{87,100,20},{111,115,20}}, {{15,160,0},{34,120,0},{55,135,0},{75,170,0}}}; float u0,u1,u2,u3,v0,v1,v2,v3; float q10,q11,q12,q13,du,dv; float q[n+1][n+1][3],q20[3],q21[3],q22[3],q23[3],q30[3],q31[3],q32[3],q33[3]; float x,y; printf(\"input j:(0---bezier, 1---B_spline)\\n\"); scanf(\"%d\ driver=DETECT;mode=0; initgraph(&driver,&mode,\"D:\\\\TC\"); setbkcolor(1); setcolor(15); for(i=0;i<=3;i++) {for(k=0;k<=3;k++) {x=(-0.7071*p[i][k][0]+0.7071*p[i][k][1]+200)*2-300; y=(0.4082*p[i][k][0]+0.4082*p[i][k][1]-0.8165*p[i][k][2]+200)*2-300; if(k==0)moveto(x,y);lineto(x,y); 19 计算机图形学实验报告 计算机072 070814082周蔓 } } for(i=0;i<=3;i++) {for(k=0;k<=3;k++) {x=(-0.7071*p[k][i][0]+0.7071*p[k][i][1]+200)*2-300; y=(0.4082*p[k][i][0]+0.4082*p[k][i][1]-0.8165*p[k][i][2]+200)*2-300; if(k==0)moveto(x,y);lineto(x,y); } } du=dv=1.0/n; for(i=0;i<=n;i++) { u0=(i*du)*(i*du)*(i*du);u1=(i*du)*(i*du);u2=i*du;u3=1; if(j==0) {q10=u0*(-1)+u1*3+u2*(-3)+u3*1;q11=u0*3+u1*(-6)+u2*3; q12=u0*(-3)+u1*3;q13=u0*1;} if(j==1) {q10=(u0*(-1)+u1*3+u2*(-3)+u3*1)/6; q11=(u0*3+u1*(-6)+u3*4)/6; q12=(u0*(-3)+u1*3+u2*3+u3*1)/6;q13=(u0*1)/6;} for(k=0;k<=2;k++) { q20[k]=q10*p[0][0][k]+q11*p[1][0][k]+q12*p[2][0][k]+q13*p[3][0][k]; q21[k]=q10*p[0][1][k]+q11*p[1][1][k]+q12*p[2][1][k]+q13*p[3][1][k]; q22[k]=q10*p[0][2][k]+q11*p[1][2][k]+q12*p[2][2][k]+q13*p[3][2][k]; q23[k]=q10*p[0][3][k]+q11*p[1][3][k]+q12*p[2][3][k]+q13*p[3][3][k]; if(j==0) 20 计算机图形学实验报告 计算机072 070814082周蔓 {q30[k]=q20[k]*(-1)+q21[k]*3+q22[k]*(-3)+q23[k]*1; q31[k]=q20[k]*3+q21[k]*(-6)+q22[k]*3; q32[k]=q20[k]*(-3)+q21[k]*3; q33[k]=q20[k]*1;} if(j==1) {q30[k]=(q20[k]*(-1)+q21[k]*3+q22[k]*(-3)+q23[k]*1)/6; q31[k]=(q20[k]*3+q21[k]*(-6)+q22[k]*3)/6; q32[k]=(q20[k]*(-3)+q22[k]*3)/6; q33[k]=(q20[k]*1+q21[k]*4+q22[k]*1)/6;} } for(m=0;m<=n;m++) { v0=(m*dv)*(m*dv)*(m*dv);v1=(m*dv)*(m*dv);v2=m*dv;v3=1; for(k=0;k<=2;k++) {q[i][m][k]=q30[k]*v0+q31[k]*v1+q32[k]*v2+q33[k]*v3;} } } setcolor(4); for(i=0;i<=n;i++) {for(m=0;m<=n;m++) {x=(-0.7071*q[i][m][0]+0.7071*q[i][m][1]+200)*2-300; y=(0.4082*q[i][m][0]+0.4082*q[i][m][1]-0.8165*q[i][m][2]+200)*2-300; if(m==0)moveto(x,y); lineto(x,y); } } for(m=0;m<=n;m++) {for(i=0;i<=n;i++) {x=(-0.7071*q[i][m][0]+0.7071*q[i][m][1]+200)*2-300; 21 计算机图形学实验报告 计算机072 070814082周蔓 y=(0.4082*q[i][m][0]+0.4082*q[i][m][1]-0.8165*q[i][m][2]+200)*2-300; if(m==0)moveto(x,y); lineto(x,y); } } if(j==0) { printf(\"3Bezier curved surface\");} if(j==1) { printf(\"3B_Splline curved surface\");} outtextxy(270,270,\"this is zhouman's homework\"); setcolor(3); settextstyle(TRIPLEX_FONT,HORIZ_DIR,1); sprintf(str,\"%s\ outtextxy(120,430,str); getch(); closegraph(); } 22 计算机图形学实验报告 计算机072 070814082周蔓 7、 二维图形的缩放、旋转,平移,组合变换 (1)思想算法: 在齐次坐标理论下,二维图形几何变换矩阵可用下式表示: k(x)xk,k0,1,2naTbcdefghi t00平移变换:[x* y* 1] =[x y 1] * 0s0 =[t*x s*y 1] 001100比例变换:[x* y* 1]=[x y 1] *010 =[m+x n+y 1] mn1 旋转变换:在 平面上的二维图形饶原点逆时针旋转Ө角,变换矩阵为 ө] cos[x* y* 1]=[x y 1] * sin0sincos000 = [x*cosө-y*sin1 复合变换:以上各种变换矩阵都是以原点为参照点,当以任意参照点进行变换的 时 候,我们就要用到复合变换矩阵。 (2)、程序实现: 用直线命令画出一个齿(或六边形的一半)→利用旋转变换或对称变换矩阵 实现对其余部分的绘制→调试运行程序→输出图形→分析结果→结束。 void tf1(float sq,float cq,int xp,int yp) { t[0][0]=cq; t[0][1]=sq; t[0][2]=0; t[1][0]=-sq;t[1][1]=cq; t[1][2]=0; t[2][0]=xp; t[2][1]=yp; t[2][2]=1; } void tf2() { float x,y; x=pp[j][0];y=pp[j][1]; pp[j][0]=x*t[0][0]+y*t[1][0]+t[2][0]; 23 计算机图形学实验报告 计算机072 070814082周蔓 pp[j][1]=x*t[0][1]+y*t[1][1]+t[2][1]; } main() { int gdriver,gmode,xp=300,yp=200; float p[][2]={{80,1},{80,8},{99,17},{97,26},{76,26}}; float i,t[3][3]; gdriver=DETECT; registerbgidriver(EGAVGA_driver); initgraph(&gdriver,&gmode,\"d:\\\c\"); setbkcolor(3); cleardevice(); setcolor(9); circle(xp,yp,70); circle(xp,yp,20); circle(xp,yp,40); circle(xp,yp,5); circle(xp,yp,2); circle(xp,yp,45); setlinestyle(0,0,6); for(i=0;i<6;i=i+0.3142) {tf1(sin(i),cos(i),xp,yp); for(j=0;j<5;j++) {pp[j][0]=p[j][0];pp[j][1]=p[j][1];tf2();} for(j=0;j<4;j++) line(pp[j][0],pp[j][1],pp[j+1][0],pp[j+1][1]); delay(10000); } getch(); closegraph(); } 24 计算机图形学实验报告 计算机072 070814082周蔓 8. 图形三视图变换 编写三维变换算法程序→检查程序的正确性→分段调试程序→输入给出的三维形体各顶点的坐标→执行变换→对算法程序进行必要的调整→更换不同的形体数据继续变换→结束。 程序实现: #include a[14][4]={{30,0,0,1},{30,40,0,1},{0,40,0,1},{0,40,10,1},{0,30,30,1}, {0,0,30,1},{30,0,30,1},{30,10,30,1},{10,10,30,1},{10,30,30,1},{10,40,10,1}, {10,10,10,1},{30,10,10,1},{30,40,10,1}}; float t[4][4],p[14][4]; void a400() {int i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) t[i][j]=0; } void a500() { int k,i,j; for(i=0;i<14;i++) {for(j=0;j<4;j++) {p[i][j]=0; for(k=0;k<4;k++) p[i][j]=p[i][j]+a[i][k]*t[k][j];} p[i][0]=p[i][0]+280; p[i][1]=-p[i][1]+180; } setcolor(9); moveto(p[0][0],p[0][1]); for(i=0;i<14;i++) 25 计算机图形学实验报告 计算机072 070814082周蔓 lineto(p[i][0],p[i][1]); line(p[6][0],p[6][1],p[0][0],p[0][1]); line(p[7][0],p[7][1],p[12][0],p[12][1]); line(p[8][0],p[8][1],p[11][0],p[11][1]); line(p[9][0],p[9][1],p[4][0],p[4][1]); line(p[10][0],p[10][1],p[3][0],p[3][1]); line(p[13][0],p[13][1],p[10][0],p[10][1]); line(p[1][0],p[1][1],p[13][0],p[13][1]); getch(); } main() {int driver,mode,i,j; driver=DETECT; initgraph(&driver,&mode,\"d:\\\c\"); setbkcolor(3); a400(); t[0][0]=0.7071*3; t[0][1]=-0.4082*3; t[1][0]=-0.7071*3; t[1][1]=-0.4082*3; t[2][1]=0.8165*3; t[3][3]=1; a500(); closegraph(); } 26 计算机图形学实验报告 计算机072 070814082周蔓 四、实验总结 在实验过程中,尽管过程中任由许多不会的地方,而且有待于今后的提高和改进,但我加深了对书本上知识的理解与掌握,同时也学到了很多书本上没有东西,并积累了一些宝贵的经验,这对我以后的学习与工作是不无裨益的。 由于本实验采用C语言编程,而C语言在图形界面的制作方面较其他面向对 象语言而言没有优势,但是在实验基本的图形绘制方面,只要选择好算法并加以实施也能够实现。本实验只是完成了一部分主要的功能,而每种功能都只选用了其中一种算法,但是在完成的过程中,我也很深刻地了解和认识了各种算法,留下了印象。但是未能实现整个画图板界面还是很遗憾,我将继续努力把它完善。 我需要完成的功能主要有以下几点: (1)、汉字的编写功能 (2)、投影变换 (3)、隐藏面消隐 (4)、三维图形变换等 参考文献 [1] 倪明田,吴良芝 ,计算机图形学, 北京:北京大学出版社,2000。 [2] 孙家广等 ,计算机图形学, 北京: 清华大学出版社 ,2002。 [3] 王飞 ,计算机图形学基础,北京:北京邮电大学出版社, 2002。 [4] 王汝传,邹北骥,计算机图形学,北京:人民邮电出版社,2003。 [5] 杨钦.计算机图形学.清华大学出版社,2005(3)。 [6] 郭玲文.精通AutoCAD.科学出版社,2001(8)。 27 因篇幅问题不能全部显示,请点此查看更多更全内容