首页 热点资讯 义务教育 高等教育 出国留学 考研考公
您的当前位置:首页正文

计算机图形学实验报告

2022-04-19 来源:华拓网
 计算机图形学实验报告 计算机072 070814082周蔓

计算机图形学实验报告

一、 实验题目:

利用计算机编程语言绘制图形,主要实现以下内容: (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(y0for(y=y0;y<=y1;y++) putpixel(x0,y,color); else

for(y=y0;y>=y1;y--) putpixel(x0,y,color);

}

else if(x0dy = y1-y0; dx = x1-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(xif (d>0)

{ y--;d +=incrP1;}

else

d +=incrP2; x++;

putpixels(x,y,color,n); } } } else if(x0>x1) { if(y03

计算机图形学实验报告 计算机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 (x0)

{ 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(xif(d<0) {

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)递推出后继的像素(xi1,yi1,r)。根据条件得到

1131yi[yi,r,yi,r)yi1[yi,r,yi,r)

2222yi1,ryi,r 当di0 y1 当d0ii,r2di4b(2xi3) 当di0di1 22di4b(2xi3)8a(yi,r1) 当di0 6

计算机图形学实验报告 计算机072 070814082周蔓

(x0,y0,r)(0,b)初始条件为d04F(1,b1)4b24a2ba2,对于分界点下方的弧段,可类似

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(xd=d+4*sb*(2*x+3); 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(yd=d+4*sa*(2*y+3); y++; } else {

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{ side_count++; if(k!=n) tem=y[k+1]; else tem=y[1];

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]put_in_sides_list(int entry,int x1,int y1,int x2,int y2,int next_y) { int maxy; float x2_temp,x_change_temp; x_change_temp=(float)(x2-x1)/(float)(y2-y1); x2_temp=x2; if((y2>y1)&&(y2next_y)) { y2++; x2_temp+=x_change_temp; } } maxy=(y1>y2)? y1:y2;

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_sprocess_x_intersections(int first_s,int last_s) { int k; x_int_count=0; for(k=first_s;k0) { x_int_count++; sort_on_x(k,first_s); } } }

sort_on_x(int entry,int first_s)

{ while((entry>first_s)&&(sides[entry].x_intswap(EACH_ENTRY *x,EACH_ENTRY *y) { int i_temp; float f_temp; i_temp=x->y_top; x->y_top=y->y_top; y->y_top=i_temp; f_temp=x->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;k0) { sides[k].delta_y--;

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(xright) d[1]=1; if(y>bottom) d[2]=1; if(y16

计算机图形学实验报告 计算机072 070814082周蔓

6、自由曲线与曲面的绘制 6.1、生成Bezier曲线

(1)算法思想

利用Bezier曲线造型时,如果其次数太高,固然能表示复杂的形状,但同时造成计算复杂度增加,而二次Bezier曲线表示能力有限,故下面我们仅讨论三次Bezier曲线的矩阵表示和计算机生成。

(1) 矩阵表示

三次Bezier曲线的定义式为:

P(t)PBii,3(t), t[0,1]

i03将其分解为两个矢量的点积为:

B0,3(t)B(t)1,3 P(t)[P0,P,P,P]123B(t)2,3B3,3(t)取Bezier曲线的几何矩阵GB[P0,P1,P2,P3],则有:

C30(1t)312C(1t)3P(t)GB2GB1C3(1t)33C3t13t3t2t3233t6t3tGB3t23t33t1 -3 3 -10 3 -6 30 0 3 -30 0 0 11tGMT

BBt23t得到三次Bezier曲线的基矩阵为:

1 -3 3 -10 3 -6 3 MB0 0 3 -30 0 0 1(2) 三次Bezier曲线的生成

Bezier曲线P(t)用的参数表示法,因此将区间[0,1]分成N等份,确定了控制点后,每取一个ti都对应一个三维的点Di(xi,yi,zi)。这样,在每两个Di和Di1之间画一条直线,再将该这些直线段投影到二维平面,就可以得到我们需要的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)PBiji0j0i,3(u)Bj,3(v)v2(0u,v1)v1]TP01P11P21P31P01P12P22P32P01P13P23P33[u3u23u33001]NPNT[v310NT0018

1

3N 3 1

TTUNPNV

630P00PP10P20P30 计算机图形学实验报告 计算机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,k0,1,2naTbcdefghi

t00平移变换:[x* y* 1] =[x y 1] * 0s0 =[t*x s*y 1]

001100比例变换:[x* y* 1]=[x y 1] *010 =[m+x n+y 1]

mn1

旋转变换:在 平面上的二维图形饶原点逆时针旋转Ө角,变换矩阵为 ө]

cos[x* y* 1]=[x y 1] * sin0sincos000 = [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 #include int

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

因篇幅问题不能全部显示,请点此查看更多更全内容