Computer Graphics
Report Of course experiment
计算机图形学课程实验
报 告
实验题目 设计算法绘制直线与圆 班 级 姓 名 学 号 指导教师 日 期
实验
实验说明
2
设计算法绘制直线与圆
试验目的: 掌握直线和圆的基本生成算法思想,并上机编程实现相应的算法。 试验地点: 教九楼401 数学系机房
实验要求(Direction): 1. 每个学生单独完成;2.开发语言为TurboC或C++,也可使用其它语言;3.请在自己的实验报告上写明姓名、学号、班级;4.每次交的实验报告内容包括:题目、试验目的和意义、程序制作步骤、主程序、运行结果图以及参考文件;5. 自己保留一份可执行程序,考试前统一检查和上交。
实验内容
实验题一
1.1实验题目
1).用DDA法在屏幕上画一条具有三个像素宽的直线段L1。要求:(1)直线段L1的两个端点坐标和画线颜色都要求可以随机输入;(2)要求输出直线段L1上的各点坐标;(3)画出直线的同时要求标明两端点坐标。
2).将课堂所讲的斜率0 1.了解如何利用C语言和图形函数进行绘图; 2. 熟悉并掌握C语言的图形模式控制函数,图形屏幕操作函数,以及基本图形函数; 3. 通过对Turbo C进行图形程序设计的基本方法的学习,能绘制出简单的图形; 4. 熟悉并掌握DDA法在屏幕上画一条具有三个像素宽的直线段L1以及通用的中点画线算法。通过DDA法及用的中点画线算法,了解图形系统初始化、图形系统关闭和图形模式的控制,并熟练运用图形坐标的设置,包括定点、读取光标以及图形颜色的设置。 1.3程序制作步骤(包括算法思想、算法流程图等) 1.自动搜索显示器类型和显示模式,初始化图形系统,通过printf、scanf语句控制线段的端点坐标和画线颜色的自由输入; y2y1yk 2. DDAline:设直线之起点为(x1,y1),终点为(x2,y2),则斜率k为: x2x1x则有: ⑴.可通过计算由x方向的增量x引起y的改变生成直线。由yi1yiy - 1 - (yi为直线上某步的初值)则yi1yiy2y1xyikx x2x1⑵.也可通过计算由y方向的增量y引起x的改变生成直线。由xi1xix(xi为直线上某步的初值)则:xi1xix2x11yxiy y2y1k3.Midpointline: ⑴.假定X坐标为xp的各像素点中,与直线最近点已确定为(xp,yp) (用实心小圆表示),那么下一个与直线最近的象素点只能是正右方的p1(xp1,yp)或右上方xxp1p2(xp1,yp1)两者之一。 ⑵. 再以M表示P1与P2的中点,即M(xp1,yp0.5)又设Q是理想直线与垂直线xxp1的交点 。显然有: ①.当M在Q的下方,则P2 离直线 近,应取为下一个象素点; ②.当M在Q的上方,则P1离直线 近,应取为下一个象素点。 ③.当M和Q重合,则P 1和P2离直线 一样近,两者均可取为下一个象素点 1.4主程序 1.4.1 DDA算法 #include \"graphics.h\" #include DDAline(int x1, int y1, int x2, int y2, int c) { float delta_x = 0; float delta_y = 0; float x = 0; float y = 0; - 2 - int dx= 0; int dy = 0; int steps = 0; int k = 0; dx=x2-x1; dy=y2-y1; if (abs(dx)>abs(dy)) { steps=3*abs(dx); } else { steps=3*abs (dy); } delta_x=(float)dx / (float)steps; delta_y=(float)dy / (float)steps; x=float(x1); y=float(y1); for (k=1; k<=steps;k++) { putpixel(int(x+0.5), int(y+0.5), c); x+=delta_x; y+=delta_y; } return 0; } void main() { char t[100] = {0}; int x1 = 0; int y1 = 0; int x2 = 0; int y2 = 0; int c = 0; void dda_line(int x1,int y1,int x2,int y2,int c); int graphdriver=DETECT,graphmode; initgraph(&graphdriver,&graphmode,\"D:\\\\TC\"); printf(\"输入两端点坐标:\\n\"); - 3 - /*初始化图形系统*/ } scanf(\"<%d,%d>,<%d,%d>\ printf(\"输入画线颜色:\\n\"); scanf(\"%d\ DDAline(x1,y1,x2,y2,c); sprintf(t,\"(%d,%d)\outtextxy(x1,y1,t); sprintf(t,\"(%d,%d)\outtextxy(x2,y2,t); getch(); /*等待按一键结束*/ closegraph(); /*关闭图形系统,回到文本模式*/ 1.4.2 中点画线算法 #include MidpointLine(int x1,int y1,int x2,int y2,int c) { int a = 0; int b = 0; int d1 = 0; int d2 = 0; int d = 0; int x = 0; int y = 0; float m = 0; if (x2 b=x2-x1; if (b==0) { m=-1*a*100; } else { m=(a/(x1-x2)); } x=x1; y=y1; putpixel(x,y,c); if (m>=0 && m<=1) { d=2*a+b; d1=2*a; d2=2*(a+b); while (x - 5 - d+=d1; } else { x++; d+=d2; } putpixel(x,y,c); } } else if (m>1) { d=a+2*b; d1=2*(a+b); d2=2*b; while (y putpixel(x,y,c); } } else { d=a-2*b; d1=-2*b; d2=2*(a-b); while (y>y1) { if (d<=0) { x++; y--; d+=d2; } - 6 - else { y--; d+=d1; } putpixel(x,y,c); } } return 0; } void main() { char t[100] = {0}; int x1 = 0; int y1 = 0; int x2 = 0; int y2 = 0; int c = 0; int graphdriver=DETECT,graphmode; initgraph(&graphdriver,&graphmode,\"D:\\\\TC\"); /*初始化图形系统*/ printf(\"输入两端点坐标:\\n\"); scanf(\"<%d,%d>,<%d,%d>\ printf(\"输入画线颜色:\\n\"); scanf(\"%d\ MidpointLine(x1,y1,x2,y2,c); sprintf(t,\"(%d,%d)\ outtextxy(x1,y1,t); sprintf(t,\"(%d,%d)\ outtextxy(x2,y2,t); getch(); /*等待按一键结束*/ closegraph(); /*关闭图形系统,回到文本模式*/ } 1.5运行结果图 1.5.1 DDA算法 - 7 - 图1.5.1DDA算法运行结果截图 图1.5.2DDA算法运行结果截图 1.5.2 中点画线算法 图1.5.3中点画线算法当k<=1时运行结果截图 - 8 - 图1.5.4中点画线算法当k<=1时运行结果截图 图1.5.5中点画线算法当0 图1.5.7中点画线算法当k=-1时运行结果截图 图1.5.8中点画线算法当k=-1时运行结果截图 图1.5.9中点画线算法当-1 图1.5.10中点画线算法当-1 实验题二 2.1实验题目 1).参考课堂所讲过的斜率为0~1和大于1的Bresenham画线程序,将该算法程序扩展到任一八分圆坐标空间图,从而形成一般的Bresenham画线算法。并利用Bresenham画线算法画出4条不同颜色、不同斜率的直线段L1、L2、L3、L4。要求:(1)4条直线段L1、L2、L3、L4的斜率K1、K2、K3、K4满足:0 2).参考课堂所讲过的圆心在原点,半径为R的第一个4分圆的Bresenham画圆算法程序,利用对称性将该算法程序推广到任一四分圆,从而形成一般的Bresenham画圆算法。并利用该算法画出一个圆心在点(xc, yc),半径为R,圆周颜色为color的圆。要求:(1)圆心的坐标、半径和圆周颜色都要求可以随机输入;(2)要求利用文本输出函数显示出所画圆的圆心和半径;(3)利用四向简单种子填充算法填充该圆。 2.2实验目的和意义 1.熟悉并掌握各种斜率的Bresenham画线程序 2.熟悉并掌握C语言的图形模式控制函数,图形屏幕操作函数,以及基本图形函数; 3.熟悉并掌握Bresenham画圆算法画一个完整的圆并进行填充。 2.3程序制作步骤(包括算法思想、算法流程图等) Bresenham画线算法思想步骤: 1.画起点(x1, y1). - 11 - 2.准备画下一个点,X坐标加1,判断如果达到终点,则完成。否则找下一个点,由图可知要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点。 2.1.如果线段ax+by+c=0与x=x1+1的交点y坐标大于(y+*y+1))/2则选右上那个点 2.2.否则选右下那个点。 3.画点 4.跳回第2步 5.结束 Bresenham画线算法流程图 - 12 - Bresenham画圆算法步骤: 1.首先,真实的线条是连续的,但是计算机中的线条是离散的,是由很多点组成的,那么画线的重点就是如何高效地找到这些离散的点来更好地画出想要的图形 2.实验要求用Bresenham算法实现画圆。那么首先先要了解Bresenham算法是一种什 么算法。经过查阅,我找到Bresenham直线算法和画圆算法。直线是圆的基础。 Bresenham直线算法是用来描绘由两点所决定的直线的算法,它会算出一条线段在 n 维光栅上最接近的点。这个算法只会用到较为快速的整数加法、减法和位元移位,常用于绘制电脑画面中的直线,是计算机图形学中最先发展出来的算法。 Bresenham画圆算法又称中点画圆算法,与Bresenham 直线算法一样,其基本的方法是利用判别变量来判断选择最近的像素点,判别变量的数值仅仅用一些加、减和移位运算就可以计算出来。为了简便起见,考虑一个圆 心在坐标原点的圆,而且只计算八分圆周上的点,其余圆周上的点利用对称性就可得到。 Bresenham画圆算法流程图: - 13 - 2.4主程序 2.4.1Bresenham画直线 #include\"graphics.h\" #include swap(int *a,int *b) { int tmp; tmp=*a; *a=*b; *b=tmp; } int Bresenham_line(int x1,int y1,int x2,int y2,int color) { double dx,dy,h,x,y,t; if(x1>x2){swap(&x1,&x2);swap(&y1,&y2);} dx=x2-x1; dy=y2-y1; x=x1;y=y1; putpixel(x,y,color); if(dx==0) { while(y!=y2){ putpixel(x,y,color);y++;}} if(dy==0) {while(x!=x2){putpixel(x,y,color);x++;}} if(dy!=0&&dx!=0) if(dy>0) if(dy<=dx) { h=2*dy-dx; while(x!=x2) { if(h<0) h+=2*dy; else { y++; h+=2*(dy-dx); } putpixel(x,y,color); x++; - 14 - } } else { h=2*dx-dy; while(y!=y2) { if(h<0) h+=2*dx; else { ++x; h+=2*(dx-dy); } putpixel(x,y,color); y++; } } else { t=-dy; if(t<=dx) { h=2*dy+dx; while(x!=x2) { if(h<0) { h+=2*(dy+dx); y--; } else h+=2*dy; putpixel(x,y,color); x++; } } else { h=-(2*dx*dy)-(dy*dy); while(y!=y2) { if(h<0) h+=-(2*dx*dy); - 15 - else { h+=-(2*dx*dy)-(2*dy*dy); x++; } putpixel(x,y,color); y--; } } } return 0; } main() { int x1,y1,x2,y2; char c; int color; int gdriver=DETECT,gmode; here: //color=6; //printf(\"Origin is in middle!\\nyou can input '-' minusn\"); printf(\"请输入起点坐标:\"); scanf(\"%d %d\ printf(\"请输入终点坐标:\"); scanf(\"%d %d\ printf(\"请输入画笔颜色:\"); scanf(\"%d\ initgraph(&gdriver,&gmode,\"\"); Bresenham_line(0,240,0,240,255); Bresenham_line(320,0,320,480,255); Bresenham_line(x1+320,y1+240,x2+320,y2+240,color); getch(); printf(\"\\ngo on?: (y/n)\"); c=getch(); if(c=='y'||c=='Y') goto here; } 2.4.2Bresenham画圆 //Bresenham画圆算法 #include \"graphics.h\" #include - 16 - void Bresenham_Circle(int r,int a,int b,int color) { int x,y,delta,delta1,delta2,direction; x=0; y=r; delta=2*(1-r); while(y>=0) { putpixel(a+x,b+y,color); putpixel(a-x,b+y,color); putpixel(a+x,b-y,color); putpixel(a-x,b-y,color); if(delta<0) { delta1=2*(delta+y)-1; if(delta1<=0) direction=1; else direction=2; } else if(delta>0) { delta2=2*(delta-x)-1; if(delta2<=0) direction=2; else direction=3; } else direction=2; switch(direction) { case 1: { x++; delta+=2*x+1; break; } case 2: { x++; y--; delta+=2*(x-y+1); break; } case 3: { - 17 - y--; delta+=(-2*y+1); break; } default: break; } } } void BoundaryFill4(int x,int y,int boundarycolor,int newcolor) { int color; color=getpixel(x,y); if(color!=newcolor && color!=boundarycolor) { putpixel(x,y,newcolor); BoundaryFill4 (x,y+1, boundarycolor,newcolor); BoundaryFill4 (x,y-1, boundarycolor,newcolor); BoundaryFill4 (x-1,y, boundarycolor,newcolor); BoundaryFill4 (x+1,y, boundarycolor,newcolor); } } void main() { int r,color,a,b,ncolor; int gdriver=DETECT,gmode; char m[100]={0}; printf(\"请输入圆的半径r:\"); scanf(\"%d\ printf(\"请输入圆心坐标:\"); scanf(\"%d%d\ printf(\"请输入边界颜色和填充颜色:\"); scanf(\"%d%d\ initgraph(&gdriver,&gmode,\"D:\\\\TC\"); Bresenham_Circle(r,a,b,color); BoundaryFill4(a,b,color,ncolor); sprintf(m,\"(%d,%d)\ outtextxy(a,b,m); - 18 - } getch(); closegraph(); 2.5运行结果图 图2.5.1 Bresenham画线算法当k>1时运行结果截图 图2.5.2 Bresenham画线算法当k>1时运行结果截图 图2.5.3 Bresenham画线算法当1>k>0时运行结果截图 - 19 - 图2.5.4 Bresenham画线算法当1>k>0时运行结果截图 图2.5.5 Bresenham画线算法当k<-1时运行结果截图 图2.5.6 Bresenham画线算法当k<-1时运行结果截图 - 20 - 图2.5.7 Bresenham画线算法当-1 图2.5.9 Bresenham画圆算法运行结果截图 - 21 - 图2.5.10 Bresenham画圆算法运行结果截图 实验题三 3.1实验题目 自学椭圆的Bresenham生成算法,利用对称性将该算法程序推广到任一四分圆,从而形成一般的Bresenham画椭圆算法。并上机编程画出一个圆心在点(xc, yc);沿x轴方向的长半轴长度为a, 沿y轴方向的短半轴长度为b; 圆周颜色为color的椭圆。要求:(1)椭圆心的坐标、长半轴长度为a、短半轴长度为b和圆周颜色color都要求可以随机输入;(2)要求利用文本输出函数显示出所画椭圆的圆心。 3.2实验目的和意义 1. 自学椭圆的Bresenham生成算法 2. 利用对称性将该算法程序推广到任一四分圆,编写一般的Bresenham画椭圆算法 3.熟悉并掌握椭圆弧的画法,并拓展到整个8分椭圆。 3.3程序制作步骤(包括算法思想、算法流程图等) 1. 输入椭圆的长半轴a和短半轴b。 2. 计算初始值db2a2(-b0.25),x0,yb。 3. 绘制点(x,y)及其在四分象限上的另外3个对称点。 4. 判断d的符号。若d0,则先将d更新为db2(2x3),再将 (x,y)更新为 (x1,y);否则先将d更新为db2(2x3)a2(2y2),再将(x,y)更新为 - 22 - (x1,y-1)。 5. 当b2(x1)a2(y0.5)时,重复步骤(3)和(4),否则转到步骤(6)。 6. 用上半部分计算的最后点(x,y)来计算下半部分中d的初值: db2(x0.5)2a2(y1)2a2b2 7. 绘制点(x,y)及其在四分象限上的另外3个对称点。 8. 判断d的符号。若d0,则先将d更新为db2(2xi2)a2(2yi3), 再将 (x,y)更新为(x1,y-1);否则先将d更新为da2(2yi3),再将(x,y)更新为 (x,y-1)。 9. 当y0, 重复步骤(7)和(8),否则结束。 3.4主程序 #include \"graphics.h\" #include \"stdio.h\" #include \"conio.h\" void Bresenham_Ciecle(int a,int b,int p,int q,int c) { putpixel(p,q,c); int x=0; int y=b; double dt=b*b+a*a*(-b+0.25); putpixel(x+p,y+q,c); while( b*b*(x+1) < a*a*(y-0.5)) { if(dt<0) { } - 23 - dt+=b*b*(2*x+3); else { } x++; putpixel(x+p,y+q,c); putpixel(-x+p,y+q,c); dt+=b*b*(2*x+3)+a*a*(-2*y+2); y--; putpixel(x+p,-y+q,c); } putpixel(-x+p,-y+q,c); double db=b*b*(x+0.5)*(x+0.5)+a*a*(y-1)*(y-1)-a*a*b*b; while( y > 0 ) { if( db < 0) { } else { } y--; putpixel(x+p,y+q,c); putpixel(-x+p,y+q,c); db+=a*a*(-2*y+3); db+=b*b*(2*x+2)+a*a*(-2*y+3); x++; putpixel(x+p,-y+q,c); } putpixel(-x+p,-y+q,c); - 24 - } void main() { } int a = 0; int b = 0; int c = 0; int x = 0; int y = 0; char m[20]={0}; int gdriver=DETECT,gmode; printf(\"请输入长轴长和短轴长度:\\n\"); printf(\"长轴 x = \"); scanf(\"%d\printf(\"短轴 y = \"); scanf(\"%d\ printf(\"请输入椭圆的圆心坐标:\\n\"); scanf(\"%d %d\printf(\"请输入椭圆的颜色:\"); scanf(\"%d\ initgraph(&gdriver,&gmode,\"\"); Bresenham_Ciecle(a,b,x,y,c); sprintf(m,\"(%d,%d)\outtextxy(x,y,m); getch(); closegraph(); 3.5运行结果图 - 25 - 图3.5.1 Bresenham画椭圆算法运行结果截图 图3.5.2 Bresenham画椭圆算法运行结果截图 图3.5.3 Bresenham画椭圆算法运行结果截图 - 26 - 图3.5.4 Bresenham画椭圆算法运行结果截图 参考文献 [1] 王汝传,黄海平,林巧民.计算机图形学教程(第二版).北京:人民邮电出版社,2009. [2]谭浩强. C语言程序设计[M]. 北京:清华大学出版社,2005. 本次实验总结或体会 通过本次试验我看到了在计算机图形学这门课中有意义的一面,增加了我学习这门课的兴趣;但同时我也认识到了自身在语言掌握中的不足和有待加强的地方;在以后的学习中要更加努力、要多动手、多学习。 教师评分 - 27 - - 28 - 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- sarr.cn 版权所有 赣ICP备2024042794号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务