第一篇:计算机图形学实验报告(例文)
计算机图形学实验报告
0900213 38 8 郭佩佩
实验一
建立计图实验环境 1. 实验目的 为了体现面向对象的程序设计思想,本实验采用基于 Visual C 十十集成环境的 MFC 编程方法,从开发 windows 应用程序的角度,来建立一个菜单交互式绘图基本环境,为后续的实验打基础。
2. 实验内容 1)
建立菜单交互式绘图基本环境的工程文件 Vcad,运行后如图:
2)在绘图菜单的下拉子菜单下有如下菜单项:
直线
----用弹性线方法输入直线的起止点后,调用 bresenham 算法替换原来
的 moveto/lineto 算法画直线
圆/圆弧
----在该菜单选择后,可分别画圆或圆弧。
直线段裁剪----输入矩形域左上角及右下角后,产生裁剪区域;然后可输入若干条直线段,矩形域作为主裁剪域对其裁剪之。
面区填充
----输入多边形的若干顶点后,调用面区填充算法对多边形域的内部填充
之。
贝塞尔曲线----输入四顶点后,调用三次贝塞尔曲线生成算法生成贝塞尔曲线。
实验二
园和园弧的绘制算法
1.实验目的 通过园和椭圆弧生成算法的上机调试,掌握:
1)
VC++图形函数的使用方法; 2)
圆和椭圆弧的生成原理。
2.实验内容 1)以函数形式编写圆的生成算法,然后在 VCAD 绘图小系统中的绘图----圆子菜单下找到合适的程序修改点,将本实验要求你编写的画圆算法插入工程文件中,通过调试来验证你编写的画圆算法的正确性。
2)
以函数形式编写角度 DDA 椭圆弧生成算法,然后在 VCAD 绘图小系统中的绘图----圆弧子菜单下找到合适的程序修改点,将本实验要求你编写的画圆弧算法插入工程文件中,通过调试来验证你编写的画圆弧算法的正确性。
Arc(int xc,int yc,doubli r,double ts,double te){
double rad,ts1,tel,deg,dte,ta,ct,st;
int x,y,n,I;
rad=0.0174533;
tsl=ts*rad;
tel=te*rad;
if(r<5.08)
deg=0.015;
else
if(r<7.62)
deg=0.06;
else
if(r<25.4)
deg=0.075;
else
deg=0.15;
dte=deg*25.4/r;
if(tel tel+=6.28319; n=(int)((tel-tsl)/dte+0.5);if(n==0) n=(int)(6.28319/dte+0.5); ta=tsl; x=xc+r*cos(tsl); y=yc+r*sin(tsl); moveto(x,y); for(i=1;i<=n;i+++) { ta+=dte;ct=cos(ta);st=sin(ta);x=xc+r*ct;y=yc+r*st;lineto(x,y);} x=xc+r*cos(tel); y=yc+r*sin(tel); lineto(x,y); return(0);} 实验三 直线的裁剪(编码裁剪算法) 1. 实验目的 通过编码裁剪算法的设计与调试,了解二维线段的裁剪过程,提高程序设计能力与上机调试能力,达到理论与实践有机结合之目的。注:此实验已有可运行的中点裁剪算法作为参考实例,做实验时,可将中点裁剪算法替换为你编写的编码裁剪算法。 2. 实验内容 1) 以函数形式编写编码裁剪算法及相关子算法; Var xl,xr,yb,yt:real;…… procedure clip(x1,y1,x2,y2:real);label:return;type edge=(L,R,B,T); outcode=set of edge;Var c,c1,c2:outcode;x,y:real;Procedure code(x,y:real;Var c:outcode); Begin c:=[ ]; If x Else if x>xr then c:=[R]; If y Else if y>yt then c:=c+[T]; End {end of code} Begin {main} Code(x1,y1,c1);code(x2,y2,c2);While(c1<>[])or(c2<>[])do Begin if c1*c2<>[] then return;{显然不可见} c:=c1;if c=[] then c:=c2; If L in c then begin x:=xl;y:=…end;{对左边界求交} If R in c then begin x:=xr;y:=…end;{对右边界求交} If B in c then begin x:=…;y:=yb end;{对底边界求交} If T in c then begin x:=…;y:=yt end;{对顶边界求交} If c=c1 then begin x1:=x;y1:=y; code(x,y,c1)end Else begig x2:=x,y2:=y; code(x,y,c2)end End;{End of while} Line(x1,y1,x2,y2); Return: end;{end of clip} 2) 交互产生矩形裁剪框,并输入不同斜率的直线段的始、终点,先画出此直线段,然后调用裁剪算法,画出裁剪后保留的可见线段部分。 3) 在 VCAD 绘图小系统中的绘图----直线裁剪子菜单下找到合适的修改点,将本实验要求你编写的编码裁剪算法替换掉工程文件中的中点裁剪算法,通过调试来验证你编写的编码裁剪算法的正确性。 实验四 面区填充(Y-X 算法) 1. 实验目的 通过 Y-X 面区填充算法的调试,掌握: 1) 多边形面区填充算法的数据组织; 2) 利用相关性提高算法效率; 3) 奇异点的处理方法; 4) 提高程序设计能力。 2. 实验内容 1) 以函数形式编写 Y-X 面区填充算法; 2) 在 VCAD 绘图小系统中的绘图----面区填充子菜单下找到合适的修改点,将本实验要求你编写的面区填充算法插入工程文件中,通过调试来验证你编写的面区填充算法的正确性。操作时,用鼠标交互给出多边形的若干顶点,画出此多边形,然后调用你编写的 Y-X 面区填充算法填充,以自选的颜色填充多边形。 实验五 贝塞尔曲线生成算法的设计与调试 一、实验目的 在掌握曲线、曲面数学理论的基础上,通过调试,绘制 Bezier 曲线。加深同学 对数学理论的理解。通过二条 Bezier 曲线的拼接设计,掌握自由曲线的拟合方法。 二、内容和要求 1、由三次 Bezier 曲线的公式:P(t)=∑P i B i,3(t) 出发,编写生成 Bezier i=0 曲线的程序,要求如下: a) 用鼠标输入特征多边形的四点。然后调用 Bezier 曲线生成算法绘出曲线。 b) 重复上步 3—4 遍,验证你编写的算法的正确性。 typedef cptype float[4][4];float cc(int n,int i)//计算 n!/(i!(n-i)!) {int j; float a; a=1; for(j=i+1;j<=n;j++)a*=j; for(j=2;j<=n-i;j++)a/=j; return a; } float b_lend(Int i,int n,float t2)//计算 B i,n(t) {float v; v=cc(n,i);for(j= 1;j<=i;j++)v*=t2; for(j=1;j<=n-i;j++)v*=(1-t2); return v; } void bezier(float x0,float y0,float z0,float t0,int n,cptype cp2)//给定 t0,计算 f(t0){int i; float b1,g; for(i=0;i<=n;i++){b1=b_lend(i,n,t0); x0=x0+cp2[i,1]*b1;y0=y0+cp2[i,2]*b1;z0=z0+cp2[i,3]*b1;}} void draw_curv(int k,cptype cp1)//将 t 分成 k 等份,循环迭代,绘出曲线。 {int i,j,x1,y1,z1; float x,y,z,delt; delt=1.0/k; t=0; for(i=1;i<=k;i++) {x=y=z=0; bezier(x,y,z,t,3,cp1); if(t==0)moveto(x,y); else lineto(x,y); t+=delt;}} 2、将特征多边形改为五个控制点,修改程序后绘出四次曲线。 3、实现二条三次 Bezier 的拼接,并使连接点处保持一阶连续。 实验小结: 实验的过程是辛苦的,特别是处理大量的数据,大量的临时变量,很容易出错,需要极大的耐心。一些计算时,例如DDA 算法画圆时,需要强制类型转换一些数据,因为遗漏导致程序出了许多奇怪的错误,调试很久才发现。另外,贝塞尔曲线的算法编写中,一些数学函数的调用也很复杂,因为不常用,所以经常翻阅 API 文档。 最困难的是因为对该图形系统的不熟悉,导致处理鼠标操作时遇到一些难题,仔细比对才得以解决。 通过本次实验,对整个图形系统有了比较透彻的了解,同时对一些数学函数的使用再次加深了印象,更重要的是掌握了许多实用的计算机图形学的算法,对 MFC 的使用有了很大提升。 这次实验中积累的经验在今后的软件开发中将使我受益匪浅。 2005 年 1 月 3 日 实 验 报 告 一、实验目的 1、掌握有序边表算法填充多边形区域; 2、理解多边形填充算法的意义; 3、增强C语言编程能力。 二、算法原理介绍 根据多边形内部点的连续性知:一条扫描线与多边形的交点中,入点和出点之间所有点都是多边形的内部点。所以,对所有的扫描线填充入点到出点之间所有的点就可填充多边形。 判断扫描线上的点是否在多边形之内,对于一条扫描线,多边形的扫描转换过程可以分为四个步骤: (1)求交:计算扫描线与多边形各边的交点;(2)排序:把所有交点按x值递增顺序排序; (3)配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边 形的一个相交区间;(4)着色:把相交区间内的象素置成多边形颜色,把相交区间外的象素置成背景色。 p1,p3,p4,p5属于局部极值点,要把他们两次存入交点表中。如扫描线y=7上的交点中,有交点(2,7,13),按常规方法填充不正确,而要把顶点(7,7)两次存入交点表中(2,7,7,13)。p2,p6为非极值点,则不用如上处理。 为了提高效率,在处理一条扫描线时,仅对与它相交的多边形的边进行求交运算。把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x坐标递增的顺序存放在一个链表中,称此链表为活性边表(AET)。 对每一条扫描线都建立一个与它相交的多边形的活性边表(AET)。每个AET的一个节点代表一条活性边,它包含三项内容 1.x-当前扫描线与这条边交点的x坐标; 2.Δx-该边与当前扫描线交点到下一条扫描线交点的x增量; 3.ymax-该边最高顶点相交的扫描线号。 每条扫描线的活性边表中的活性边节点按照各活性边与扫描线交点的x值递增排序连接在一起。 当扫描线y移动到下一条扫描线y = y+1时,活性边表需要更新,即删去不与新扫 描线相交的多边形边,同时增加与新扫描线相交的多边形边,并根据增量法重新计算扫描线与各边的交点x。 当多边形新边表ET构成后,按下列步骤进行: ① 对每一条扫描线i,初始化ET表的表头指针ET[i]; ② 将ymax = i的边放入ET[i]中; ③ 使y =多边形最低的扫描线号; ④ 初始化活性边表AET为空; ⑤ 循环,直到AET和ET为空。 将新边表ET中对应y值的新边节点插入到AET表。 遍历AET表,将两两配对的交点之间填充给定颜色值。 遍历AET表,将 ymax= y的边节点从AET表中删除,并将ymax> y的各边节点的x值递增Δx;并重新排序。 y增加1。 三、程序源代码 #include “graphics.h” #define WINDOW_HEIGHT 480 #define NULL 0 #include “alloc.h” #include “stdio.h” #include “dos.h” #include “conio.h” typedef struct tEdge /*typedef是将结构定义成数据类型*/ { int ymax;/* 边所交的最高扫描线号 */ float x;/*当前扫描线与边的交点的x值 */ float dx;/*从当前扫描线到下一条扫描线之间的x增量*/ struct tEdge *next;}Edge; typedef struct point{int x,y;}POINT;/*将结点插入边表的主体函数*/ void InsertEdge(Edge *list,Edge *edge)/*活性边edge插入活性边表list中*/ { Edge *p,*q=list;p=q->next;/*记住q原来所指之结点*/ while(p!=NULL)/*按x值非递减顺序增加边表*/ { if(edge->x x)/*要插入的边的x较大不应该在当前插入*/ p=NULL; else /*要插入的边的x较小应该在当前插入*/ {q=p; p=p->next; } } edge->next=q->next;/*使欲插入之结点edge指向q原来所指之结点*/ q->next=edge;/*使q指向插入之结点*/ } int yNext(int k,int cnt,POINT *pts)/*对于多边形中的某个顶点序号k(0,1...6),返回下一顶点的纵坐标,如果这2个顶点所在边是 水平的,则顺延,即返回第(k+2)个顶点的纵坐标),cnt是顶点个数+1,pts指向多边形顶点结构体的指针*/ { int j;if((k+1)>(cnt-1))/*当前顶点为最后一个顶点,则下一个顶点为第0个顶点 */ j=0;else j=k+1;/*当前顶点不是最后一个顶点,下一个顶点为数组下标加一*/ while(pts[k].y==pts[j].y)/*扫描线扫过平行顶点,需分情况找到当前顶点下下个顶点*/ if((j+1)>(cnt-1)) j=0; else j++;return(pts[j].y);/*返回下一个顶点的y值 */ } /* 计算增量,修改AET*/ /*生成边表结点,并插入到边表中的主体函数*/ void MakeEdgeRec(POINT lower,POINT upper,int yComp,Edge *edge,Edge *edges[])/*把边结点edge,放到lower.y扫描线所在的边结点指针数组edges[]中 */ {edge->dx=(float)(upper.x-lower.x)/(upper.y-lower.y);edge->x=lower.x;if(upper.y /*创建边表的主体函数*/ void BuildEdgeList(int cnt,POINT *pts,Edge *edges[])/*建立新边表,cnt:多边形顶点个数+1,edges[]:指向活性边结点的指针数组*/ { Edge *edge;POINT v1,v2;int i,yPrev=pts[cnt-2].y;/*当前顶点的前一个顶点的y值,在当前顶点不是奇点时使用该参数*/ v1.x=pts[cnt-1].x;v1.y=pts[cnt-1].y;for(i=0;i edge=(Edge *)malloc(sizeof(Edge)); edge=(Edge*)malloc(sizeof(Edge));if(v1.y yNext*/ MakeEdgeRec(v1,v2,yNext(i,cnt,pts),edge,edges);/*确定v1,v2边较高端点的开闭*/ else MakeEdgeRec(v2,v1,yPrev,edge,edges);/*当前顶点 是奇点*/ } yPrev=v1.y;v1=v2;} } /*建立活性边表的主体函数:建立第scan条扫描线的活性边表*/ void BuildActiveList(int scan,Edge *active,Edge *edges[])/*建立扫描线scan的活性边表,把活性边结点放入扫描线scan的结点指针数组 edges[scan]中*/ { Edge *p,*q;p=edges[scan]->next;/*查找当前扫描线对应的y桶*/ while(p)/*y桶不空*/ {q=p->next;/*找到最后一个边结点,插入*/ InsertEdge(active,p);/*把更新后的边表重新插入边表中保存*/ p=q; } } /*填充一对交点的主体函数*/ void FillScan(int scan,Edge *active,int color)/*填充扫描线:填充扫描线上,且在下一结点到再下一结点之间的点*/ { Edge *p1,*p2;int i;p1=active->next;while(p1){ p2=p1->next; for(i=p1->x;i x;i++) putpixel((int)i,scan,color);/*画出图形内部的点*/ p1=p2->next;/*活性表的下一条边表 */ } } void DeleteAfter(Edge *q)/*删除链表中结点,删除边结点q的后续结点p*/ { Edge *p=q->next;q->next=p->next;/*删除结点*/ free(p);} /* 删除 y=ymax 的边 */ /*填充完后,更新活动边表的主体函数*/ void UpdateActiveList(int scan,Edge *active)/*删除扫描线scan完成交点计算的活性边,同时更新交点x域*/ { Edge *q=active,*p=active->next;while(p)if(scan>=p->ymax)/*扫描线超过边的最大y值,此条边的节点应该删掉*/ { p=p->next;deleteAfter(q);} else /*扫描线未超过边的最大y值,相应的x值增加*/ { p->x=p->x+p->dx;q=p;p=p->next;} } /*对活性边表结点重新排序的主体函数*/ void ResortActiveList(Edge *active)/*活性边表active中的结点按x域从小到大重新排序*/ { Edge *q,*p=active->next;active->next=NULL;while(p){q=p->next;InsertEdge(active,p);/*把更新后的边表重新插入边表中保存 */ p=q;} } /*多边形填充的主体程序*/ void ScanFill(int cnt,POINT *pts,int color)/*填充函数,输入:多边形顶点个数+1=cnt, 指向多边形顶点的指针数组pts*/ { Edge *edges[WINDOW_HEIGHT],*active;int i,scan,scanmax=0,scanmin=WINDOW_HEIGHT;for(i=0;i {if(scanmax if(scanmin>pts[i].y)scanmin=pts[i].y; } for(scan=scanmin;scan<=scanmax;scan++)/*初始化每条扫面线的边链表*/ {edges[scan]=(Edge *)malloc(sizeof(Edge));/*建 edges[scan]->next=NULL; } BuildEdgeList(cnt,pts,edges);/*建立有序边表*/ active=(Edge *)malloc(sizeof(Edge));“桶”*/ active->next=NULL;for(scan=scanmin;scan<=scanmax;scan++)/*扫描每条扫描线,求活性表*/ { BuildActiveList(scan,active,edges);/*建立活性边表*/ if(active->next)/*活性边表不为空*/ { FillScan(scan,active,color);/*填充当前扫描线*/ UpdateActiveList(scan,active);/*更新活化边表*/ ResortActiveList(active);/*重排活化边表*/ } } } /*开始菜单*/ void main(){ POINT pts[7];/*保存数组*/ int gdrive=DETECT,gmode;pts[0].x=100;pts[0].y=40;/*多边形顶点x、y坐标*/ pts[1].x=220;pts[1].y=140;pts[2].x=280;pts[2].y=80;pts[3].x=350;pts[3].y=300;pts[4].x=200;pts[4].y=380;pts[5].x=50;pts[5].y=280;pts[6].x=100;pts[6].y=40;/*合并桶中的新边,按次序插入到 AET 中*/ initgraph(&gdrive,&gmode,“C:TC3.0BGI”);/*设置graphic模式*/ ScanFill(7,pts,2);getch();} 四、实验结果 图1 用有序边表算法生成的多边形 五、总结与体会 实验步骤 1)分析多边形区域扫描线填充算法的原理,确定算法流程 ① 初始化:构造边表,AET表置空 ② 将第一个不空的ET表中的边插入AET表 ③ 由AET表取出交点进行配对(奇偶)获得填充区间,依次对这些填充区间着色 ④ y=yi+1时,根据x=xi+1/k修改AET表所有结点中交点的x坐标。同时如果相 应的ET表不空,则将其中的结点插入AET表,形成新的AET表 ⑤ AET表不空,则转(3),否则结束。2)编程实现 ① 首先确定多边形顶点和ET/AET表中结点的结构 ② 编写链表相关操作(如链表结点插入、删除和排序等) ③ 根据1)中的算法结合上述已有的链表操作函数实现多边形区域扫描线填充的主体功能 ④ 编写主函数,测试该算法 通过运用C语言环境下的图像显示设置,本次实验我学会了多边形区域扫描线填充的有序边表算法,设计相关的数据结构(如链表结构、结点结构等),并将实现的算法应用于任意多边形的填充,为深一步的学习做好了铺垫。 六、参考文献 [1]张家广 等编著.计算机图形学(第3版).北京:清华大学出版社,1998年9月.[2]陈传波,陆枫主编,《计算机图形学基础》,电子工业出版社,2002年3月. 0908141020 试验092 尤洋 实验1-1: 通过循环画线,实现了画四边形的功能 实验1-2: 通过循环设置顶点坐标,循环画线,实现了画7个顶点的金刚石 实验1-3: 通过填充实现了画三彩多边形 实验2-1: 实现了画各种范围不同斜率的直线 实验3-1: 通过Cohen-Sutherland算法和清屏重画实现了金刚石的区域裁剪 实验4-1: 通过不断地清屏重画实现了北极星的平移、比例、旋转、对称 实验5-1: 通过矩阵变换实现了三维图形的三视图、正轴测投影 《计算机图形学》学习报告 东西方建筑中的理性 尽管东方“木构”的暂时性文化和西方“石砌”的永久性文化氛围造成了建筑形式风格的差异,但是它们都兼有理性和感性美。从柱式的英文“order”一词,到中国古建筑等级制的基数开间,无不透露着匠人的理性思考;从古埃及绘画中为了将人的特征最大限度表现而作的头部侧面身体正面的绘画,到文艺复兴达芬奇创造的透视画法,一步步将人们引向更为理性的世界。 西方古典主义者强调构图中的主从关系,突出轴线、讲求配称;倡导理性,主张建筑的真实,反对表现感情和情绪。随之而来的比例、节奏、韵律、秩序美,是建筑区别于雕塑和绘画两大艺术的特点。 维特鲁威提出的建筑三原则:坚固、适用、美观,时时刻刻提醒着我们建筑是要被建造起来的,它是我们的“避难所”,需要理性的结构、缜密的分析和思考。时代在进步,建筑理论从勒杜克的结构理性主义发展到现在的解构主义,再也不是建筑形式适应结构的时代了,而是两者互为促进。 我们对建筑的理解不再是像路易斯康那样再去问砖想做什么,等待它做拱卷的回答。我们向大自然学习,卡拉特拉瓦创造了许多带有理性美的仿生建筑。当我们想进一步拓宽我们的思维时,我们还能向谁求助?计算机图形学为我们打开了理性思考的一扇窗。 计算机图形学对理性建筑的贡献 半个多世纪以来,计算机技术得到了飞速的发展。它的进步不仅仅使世界变得更平,信息交流更便捷,在此平台上开发的各种绘图软件更是将建筑师从传统的手工渲染画图中解放出来,也解放了结构师的工作量。用了30年的时间,计算机的速度从K(103)到T(1012),而从T到Z(1021),我们只用了10年时间。发展的速度是越来越快,我们设计方法和速度都得到了革新。这是这样一个数字化信息化的时代,才有弗兰克盖里建筑的夸张和扎哈哈迪德设计的新奇。 原来我们随手绘出的自由曲线,现在计算机都能帮我们算出是否有建造的可能,以及建筑性能也能在建造前得到分析。在创意上,计算机也能将我们模糊的概念无限发展,给它一个规则,它可能还你一个超乎想象的造型,在理性规则中生成感性而自由的建筑。 知其然,还应知其所以然,看着电视机的变薄,图像更加逼真,这变化的一切都建立在计算机图形学的架构下,了解了基础原理,才能更高效地做高质量的建筑设计。 计算机图形学的理论知识 1.相关概念 计算机图形学是主要研究通过计算机处理用集合数据和数学模型所描述的图形的原理、算法和系统。包括图形的输入、存储、运算、转换、传送和输出。数字化技术是泛指在某特定领域利用包括硬件、软件在内的计算机与电子技术以及数学或数字模型等描述的问题进行求解、模拟或分析活动的一切应用技术。 建筑数字化技术研究应用包括建筑的数字化设计和反映建筑的数字化特征在内的数字技术。而建筑数字化技术的核心几何学科就是计算机图形学。2.反映建筑数字化特征的典型图形技术 建筑的动态特征——图形显示:如奥地利格拉茨美术馆的925盏灯形成的外墙面显示屏 建筑的互动特征——图形显示:如杜瑟赫姆市的随情感变化而色彩变化的建筑物 建筑的数字特征——几何运算:如柏林Max Reinhardt大楼模型及“莫比乌斯环”变换 建筑的虚实特征——交互式图形:如法国国立图书馆(实体与网络图书馆) 设计手段和设计媒体的数字化特征——交互式图形:如纽约韩国基督教长老会教堂 而建筑性能如声环境、热环境、光环境、风环境模拟的可视化分析中都用到了图形学。3.虚拟现实技术(VR) 虚拟现实技术是计算机生成的给人多种感官刺激的虚拟世界(环境),是一种高级的人机交互系统。 虚拟现实技术的三个基本特征:沉浸感、交互性、想象力 它具有多学科的综合性,正如建筑学是一门综合的艺术,虚拟现实技术包括图像处理、图形学、计算几何、多传感器、网络、多媒体和仿真技术等。 正如课堂上老师放映的《碟中谍4》,逼真的爆炸场景,以及从皮克斯动画开始的动物毛发到最近火热的《少年派》逼真的老虎与人共存画面,虚拟现实技术的进步影响到了我们生活的方方面面,触到了我们原来想都不敢想的世界。 而VR技术在建筑行业中,有以下作用:(1)指导设计:让建筑师通过浏览观察和了解空间关系,特别是对空间大小、方向、形状和建筑元素行为的理解。(2)建筑表现与环境仿真(3)仿真施工:检查和修改施工细节、合理性和有效性 4.虚拟现实的基础与关键技术:建模与描绘 基于几何和图形学的建模和描绘技术 直接几何建模 3D扫描建模 投影视图建模 基于图像的场景描绘技术(IBR) 图像投影变形技术 光场重建技术 混合式IBR技术 IBR技术图形的绘制独立于场景的复杂性,仅仅与所要生成画面的分辨率有关。 实验三 MFC画直线 最近自己在学习如何在VC 6.0 开发环境下的使用MFC AppWizard(exe)来绘画一条直线,虽然比较简单,通过这样的练习可以帮助你熟悉MFC的开发环境以及其中的消息传递机制,希望对于像我一样初入MFC图形绘制学习的人有帮 助 第一步:构建MFC窗体 打开Visual C++ 6.0编译器 新建→工程→MFC AppWizard(exe),工程名以DrawLine为例,然后确定。为了方便,在MFC应用程序向导—步骤1当中选择“单文档”,其余所有的步骤都为默认值,直接“完成”。这样一个简单的MFC窗体就构建好了,自己不妨Compile—Build—BuildExecute一下。 第二步:编辑菜单项 选择ResourceView视窗展开Menu文件夹,左键双击IDR_DRAWLITYPE,右边就会出现菜单图形编辑界面,为了简化,我们只在添加帮助→DrawLine功能选择项。双击空白会弹出“菜单项目 属性”对话框。ID:ID_DRAW_LINE;标明: DrawLine(&D),其它的为缺省。 第三步:建立消息命令 如果此时运行该程序,你会发现帮助—DrawLine的功能选项是灰色的,原因就在于我们还没有添加该功能的消息命令相应函数。通过“查看—Message Maps—Project:DrawLine—Class name:CDrawLineView—Object IDs:ID_DRAW_LINE—选定COMMAND—Add Function„”,其它为默认,最后确定完成。现在如果再重新运行该程序的话,会发现原来的灰色已经消除了。 第四步:添加鼠标消息响应 打开ClassView视窗,右键选定CDrawLineView,选择Add Windows Messsage Handler会弹出对话框,完成CDrawLineView类的WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP三个Windows消息事件的新建。 第五步:添加响应代码 首先,在ClassView视窗中双击CDrawLineView会定位到“DrawLineView.h : interface of the CDrawLineView class”的文件,添加CDrawLineView类的成员:protected: int m_Drag;POINT m_pPrev;POINT m_pOrigin;三个成员变量。视窗中展开CDrawLineView类,双击定位OnLBUTTONDOWN()函数。在该函数消息响应 处添加如下代码: //建立好绘图的设备环境 CClientDC dc(this);OnPrepareDC(&dc); dc.DPtoLP(&point); //获取起始点坐标 m_pPrev=point;m_pOrigin=point; m_Drag=1; 然后,定位于OnMouseMove(),添加如下代码(其中关键用到了橡皮筋技术): //建立好绘图的设备环境 CClientDC dc(this); OnPrepareDC(&dc);dc.DPtoLP(&point); dc.SetROP2(R2_NOT);//橡皮筋绘图技术 //判断是否BUTTONDOWN if(m_Drag) { dc.MoveTo(m_pOrigin);dc.LineTo(m_pPrev);dc.MoveTo(m_pOrigin);dc.LineTo(point); } m_pPrev=point; 最后,在OnLBUTTONDOWN()添加代码: m_Drag=0; 程序运行效果图 实验4 实现圆的生成算法 一、实验目的 1.熟悉CDC图形程序库; 2.掌握中点画圆生成算法; 3.掌握Bresenham画圆算法。 二、实验内容 利用VisualC++6.0设计一个简易画圆绘图板,验证圆生成算法。 三、实验指导 1.生成绘图应用程序的框架,如下图所示。具体实现见第二次实验,过程不再详细说明。 2.在应用程序中增加菜单 完成相关菜单的设计,具体的效果如下图所示,并设置好相关菜单消息的映射,具体的实现在前面的实验中介绍过,再此不在详细说明。 3.在绘图函数中添加代码 通过以上步骤,得到了与菜单对应的消息映射,就可以在函数中添加代码绘制图形了。(1)利用中点画圆算法实现圆的生成(算法原理见教材)。void CDraw_CirView::OnMid(){ // TODO: Add your command handler code here CDC*pDC=GetDC();//得到绘图类指针 RedrawWindow();//重绘窗口 int x,y,x0=200,y0=200,r=100;//圆的圆心为(x0,y0),半径为r float d;x=0;y=r;d=1.25-r; pDC->SetPixel(x+x0,y+y0,RGB(255,0,0));pDC->SetPixel(y+x0,x+y0,RGB(255,0,0));pDC->SetPixel(y+x0,-x+y0,RGB(255,0,0));pDC->SetPixel(x+x0,-y+y0,RGB(255,0,0));pDC->SetPixel(-x+x0,-y+y0,RGB(255,0,0));pDC->SetPixel(-y+x0,-x+y0,RGB(255,0,0));pDC->SetPixel(-y+x0,x+y0,RGB(255,0,0));pDC->SetPixel(-x+x0,y+y0,RGB(255,0,0));while(x<=y){ if(d<0) { d=d+2*x+3; x++; } else { d=d+2*(x-y)+5; x++; y--;} pDC->SetPixel(x+x0,y+y0,RGB(255,0,0)); pDC->SetPixel(y+x0,x+y0,RGB(255,0,0)); pDC->SetPixel(y+x0,-x+y0,RGB(255,0,0)); pDC->SetPixel(x+x0,-y+y0,RGB(255,0,0)); pDC->SetPixel(-x+x0,-y+y0,RGB(255,0,0)); pDC->SetPixel(-y+x0,-x+y0,RGB(255,0,0)); pDC->SetPixel(-y+x0,x+y0,RGB(255,0,0)); pDC->SetPixel(-x+x0,y+y0,RGB(255,0,0));} } 由以上代码绘出的图形如下: (2)利用Bresenham算法生成圆(算法原理见教材)。void CDraw_CirView::OnBre(){ // TODO: Add your command handler code here CDC*pDC=GetDC();//得到绘图类指针 //RedrawWindow();//重绘窗口 int x,y,x0=200,y0=200,r=50;//圆的圆心为(x0,y0),半径为r int delta,delta1,delta2,direction;x=0;y=r;delta=2*(1-r);while(y>=0){ pDC->SetPixel(x+x0,y+y0,RGB(0,0,255)); pDC->SetPixel(x+x0,-y+y0,RGB(0,0,255)); pDC->SetPixel(-x+x0,y+y0,RGB(0,0,255)); pDC->SetPixel(-x+x0,-y+y0,RGB(0,0,255)); if(delta<0) { delta1=2*(delta+y)-1; if(delta<=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:y--; delta+=(-2*y+1); break; } } } 由以上代码绘出的图形如下: (3)以上是本次实验的基本部分,利用中点画圆和Bresenham画圆算法实现的基本图形的绘制。能不能利用该算法,完成一些复杂图形的生成,比如利用基本的画圆算法绘制一个奥运五环。甚至根据画圆算法,实现二次曲线的生成,如椭圆的生成等等。请同学们认真考虑,完成这部分的内容,上机调试。 四、思考 1.如何实现圆心为任意位置的圆的绘制; 2.两种画圆算法的比较。第二篇:计算机图形学实验报告
第三篇:计算机图形学实验报告
第四篇:计算机图形学学习心得
第五篇:计算机图形学实验