北京工商大学.docx
《北京工商大学.docx》由会员分享,可在线阅读,更多相关《北京工商大学.docx(14页珍藏版)》请在冰豆网上搜索。
北京工商大学
北京工商大学
计算机图形学实验报告
试验名称计算机图形学实验共10页
成绩实验日期2005年5月日
班级微机024班组别交报告日期2005年6月15日
学号0214020415姓名欧阳锦林
同组学生教师审批签字
图形学实验报告
——微机024班15号欧阳锦林
一、实验目的:
通过本实验,使自己了解计算机图形学的有关原理、算法及系统,掌握基本图形显示程序设计方法,及二维和三维图形变换程序设计方法,为进一步学习计算机辅助设计方面的技术知识打下基础。
二、实验内容和要求:
1、实验内容
1直线和圆的生成,设定屏幕图形工作方式,彩色象素的读写,直线和圆的扫描转换。
2多边形的裁剪和填充
3图形变换:
二维变换、及投影、透视变换
2、上机实验要求
上机实验是巩固课堂内容。
增强感性认识。
实验后要求学生认真编写实验报告,作为学生平时成绩的依据。
三、实验报告:
1、实验环境:
VStudio6.0的VC6.0,MFC
2、实现功能:
a)直线和圆的生成,直线和圆的扫描转换。
并且实现了用鼠标点击取点的交互功能。
b)多边形的裁剪和填充,实现了点扫描与直线扫描多边形。
c)直线剪裁,并可以自动判断与某条或某些条直线可剪裁,剪裁结果是一条线段生成两到三条线段,并可在文档中保存。
d)图形变换:
二维变换:
平移、旋转、缩放功能,其中平移已实现了鼠标点击取点的交互功能。
e)提供了用户对对象的选择,再在在被选择的对象上进行相应操作。
f)实现了文档存储与打开。
3、文件格式:
1、Graph1.txt文件格式是:
第一行表示有3种类形的图元数据,在本程序中为3,分别为直线,圆,多边形,第二行为第一个数据为类型,1表示为直线容器,第二个数据3表示此直线容器(用双链表实现)中有3条直线。
下面3行的格式相同,分别是颜色,起点、终点的x、y坐标。
第六行中3表示类型3是多边形,2表示多边形个数。
再下面就是各个多边形的信息的,0表示不用填充,15550是颜色值,3表示3边形。
下面三行是三个顶点的x、y坐标。
11-16行信息同理。
17行2表示类型2为圆,1表示1个,18行各个数据分别表示,是否填充、颜色、圆心x、y坐标、半径。
2、可以直接用记事等不带格式的文本编辑器按文件格式进行手工修改,注意:
一定要按格式,否则将不能生成你想要的图元。
4、所用数据结构:
1、GraphObject:
本程序得用一个数据结构把所有的图元装入了,并可以根据不同的类型,做不同的动作,类的定义如下:
//GraphObject是用来存放各种图形对象的,根据type的不同,
//object做不同的类型转换.
classGraphObject
{
private:
void*object;
inttype;
public:
GraphObject();
GraphObject(void*Object,intType);
virtual~GraphObject();
//根据type的不同,做不同的动作。
boolaction(CDC*pCDC);
//根据type的不同,保存不同为格式。
boolsave(ofstream&out);
};
再用CListGraphList;
容器把所有的对象都装入进去了。
当然,后来为了方便,再加了三个容器,这个容器的作用就不大了,可它却体现了大自然的面向对象的基本原理,值得关注。
2、Matrix:
#definePI3.1415926
//3*3矩阵类:
classMatrix
{
public:
Matrix();
Matrix(constMatrix&mat);
Matrix(inttx,intty);
Matrix(floattx,floatty);
virtual~Matrix();
floatarray[3][3];
voidSetIdentity();//设置对角为1,其余为0
Matrix&operator*(constMatrix&mat);//矩阵乘法.
Matrix&operator+(constMatrix&mat);//矩阵加法
//将点通过矩阵转换为另一个点.
POINT&pointTrans(POINT&point);
};
3、MidLine:
#definePrecision5//此为选择对象的精确度
//线段类:
classMidLine
{
public:
MidLine();
MidLine(intx0,inty0,intx1,inty1);
MidLine(POINTPoint0,POINTPoint1);
virtual~MidLine();
voidMidPointLine(CDC*pCDC);
voidsetColor(COLORREFColor);
boolSelectIt(POINTpoint);
//二维复合变换
voidmove(POINTpoint);
voidrotate(floata,CPointrefpt);
voidscale(floatsx,floatsy,CPointrefpt);
boolselect;
POINTpoint0,point1;
COLORREFcolor;
private:
voidMidPointLine0(intx0,inty0,intx1,inty1,intcolor,intindex,CDC*pCDC);
};
4、MidCircle:
#definePI3.1415926
//3*3矩阵类:
classMatrix
{
public:
Matrix();
Matrix(constMatrix&mat);
Matrix(inttx,intty);
Matrix(floattx,floatty);
virtual~Matrix();
floatarray[3][3];
voidSetIdentity();//设置对角为1,其余为0
Matrix&operator*(constMatrix&mat);//矩阵乘法.
Matrix&operator+(constMatrix&mat);//矩阵加法
//将点通过矩阵转换为另一个点.
POINT&pointTrans(POINT&point);
};
5、Polygon:
#include
#include
#include
#definePrecision5//此为选择对象的精确度
//扫描线算法中的“边”数据结构表示
structEdge{
inty;//边的上端点的y坐标
floatx;//AEL中当前扫描线与边的交点(或ET中边的下端点的x坐标)
floatdeltax;//边的斜率的倒数
//定义边类型的大小比较关系(用于排序)
friendbooloperator<(constEdge&,constEdge&);
};
//结点为边的链表的数据类型
typedefstd:
:
listEgList;
//Et表数据类型
typedefstd:
:
mapEtType;
//多边形类:
classpolygon
{
public:
//多边形数据结构表示
intcount;//多边形顶点数
POINT*pPointArray;//多边形顶点数组
COLORREFcolor;
boolFill;//是否填充
boolselect;//是否为当前选择对象
boolSelectIt(POINTpoint);//判断当前点是否选中多边形
EtTypeet;
EgListael;
//四个构造函数
polygon();
polygon(intCount,POINT*pPoint);
polygon&operator=(constpolygon&py);
virtual~polygon();
//下面四个函数为扫描填充多边形
inttoInt(floata,inttype);
voidinit();
voiddrawLine(intxLeft,intxRight,inty,CDC*pDC);
voidLineScan(CDC*pDC);
voidsetColor(COLORREFColor);
//画多边形,根据Fill是否填充.
voiddrawPoly(CDC*pCDC);
//二维复合变换
voidmove(POINTpoint);
voidrotate(floata,CPointrefpt);
voidscale(floatsx,floatsy,CPointrefpt);
private:
polygon(constpolygon&py);
};
5、调试经验:
我在调试这个程序的时候遇到了一些“低级”错误,也理解了关于C++的一些高级主题,为方便大家的交流,也方便自已以后的学习,我将这此经验都用注释写在相应的地方了。
试举几例:
(1)、polygon&polygon:
:
operator=(constpolygon&py){
//注意下面两行代码,是必须的,
//一定要释放对象以前指向的内存区。
//详细情况请看polygon:
:
polygon(constpolygon&py)的注释
if(pPointArray!
=NULL)
delete[]pPointArray;
count=py.count;
pPointArray=newPOINT[count];
color=15550;
Fill=py.Fill;
select=py.select;
for(inti=0;ipPointArray[i]=py.pPointArray[i];
return*this;
}
polygon:
:
polygon(constpolygon&py)
{
//if(pPointArray!
=NULL)
//delete[]pPointArray;
//!
!
!
!
//当用polygonp(py)时,p.pPointArray不会自动设为空!
!
//此时用delete将会产生寻常!
!
!
//然而:
又如何保证在赋值前释放以前的空间呢!
!
?
?
//解答:
test类:
test.h,注意:
如果写成:
testc=a则会调用其拷贝构造函数
//只有写成testc;c=a;才会调用operator=
//基于此,可把拷贝构造函数设为私有,才可保证生成对象时一定会调用默认
//构造函数!
//但是,如果这样,则在使用这个类时会遇上很多"阻碍",那就是你要避免系统
//"自动"调用你的拷贝构造函数,比如当你的函数形参是对象而不是引用时,
//因此,这时你最好检查你的函数,使其用引用做为形参,如果不想因函数改变
//形参,则设为引用即可.
//也许,C++在扩充C时加入了一个引用这种奇怪的数值引用方式.
count=py.count;
pPointArray=newPOINT[count];
color=15550;
Fill=py.Fill;
select=py.select;
for(inti=0;ipPointArray[i]=py.pPointArray[i];
}
polygon:
:
polygon(intCount,POINT*pPoint)
{
//由于用此种构造函数时,不会设置pPoint为NULL,
//故不用下面两行代码
//否则可能删除未初始化指针,产生异常。
//if(pPointArray!
=NULL)
//delete[]pPointArray;
……
(2)、//画多边形,根据Fill选择是否填充.
voidpolygon:
:
drawPoly(CDC*pCDC)
{
for(inti=0;i{
MidLineline(pPointArray[i],pPointArray[i+1]);
line.setColor(color);
line.MidPointLine(pCDC);
}
MidLineline(pPointArray[count-1],pPointArray[0]);
line.setColor(color);
line.MidPointLine(pCDC);
if(Fill)
{
LineScan(pCDC);
//下面是用点填充算法实现填充!
//由于递归算法太过消耗资源,故将其注释掉
//改成线扫描
/*intx=0,y=0;
for(i=0;i//!
!
一个count-1用了我1个半小时
//还是上厕所的时候突然想到,for语句控制错误!
!
//可见编程最是要头脑清醒!
!
…………
(3)、POSITIONpos=polygonList.GetHeadPosition();
//注意!
!
:
(CList*)object一定要用()号括起来!
!
6、程序特点:
(1)、由于本程序是为了实现图形学的各种算法,因此,哪怕是画直线这样的事也都没有调用MFC提供的函数来实现,全部都是自己编写的。
(2)、结构较严谨,在编写的过程中,我注意到了类的结构严谨,文档类视图类的分工合作明确。
但还是很遗留了很多冗繁的地方,因为有的一开始就没有注意,到后来也就没有改了。
(3)、保存了调试信息,我在编写代码是时候喜欢由接口到实现,由简单到复杂的顺序编写,最后我保存了那些有价值的调试代码做为注释,以便以后学习与修改。
(4)、纠正并完善了某些书上的算法:
我用的图形参考书是:
《计算机图形学》倪明田、吴良芝编著,北京大学出版社,但其中很多算法没有用
(1)、//此算法在这里有问题,可能是因为我们所用的坐标系
//原点在左上角而不是程序假设的左下角.
/*P0(x0,y0)P1(x1,y1)为待裁剪线段*/
/*rect为裁剪窗口*/
boolCGraphView:
:
CohenSutherlandLineClip(floatx0,floaty0,floatx1,floaty1,CutRect
*rect,POINT&point0,POINT&point1)
(2)、boolCGraphView:
:
CohenSutherlandLineClip(floatx0,floaty0,floatx1,floaty1,CutRect
*rect,POINT&point0,POINT&point1)函数中:
//注意,书上此行代码有问题!
!
//原句是:
x=x0+(x1-x0)*((float)rect->ymin-x0)/(y1-y0);
//书111面
(3)、在直线的中点算法中,voidMidLine:
:
MidPointLine0(intx0,inty0,intx1,inty1,intcolor,intindex,CDC*pCDC)
{
…………
d+=incrE;
x++;//注意:
书本47面的的程序少了这行代码,应该加上.
……
(4)、直线的中点算法书上只是实现1/8的区域,要以任意点画直线,需要自己做一些转化。
7、待扩充内容:
本程序还有很多地方值得改进,由于时间不够,先做到这里,但现在因为我采用了各种类来定义不同的图元,因此,要扩充是很容易的。
需要扩充的地方有:
图元变换的交互式实现(包括鼠标的变形)、图形类型的添加,如,椭圆,圆弧等,还有就是调色板对颜色的控制。
四、实验总结:
1、实验收获与体会:
比较起这个学期的其他课程来说,我这个图形实验上用的时间是最多的,当然收获也是最大的,做完实验后,不免清点一下:
a、对C++语言的进一步应用与理解,最大的收获便是引用,我以前一直对引用总是一知半解,知其然不知其所以然,现在明白了,在C++这种语言中,为什么要在C语言的基础上加入引用呢?
我觉得是基于以下几个方面的原因:
1、高效:
如果用对象做为函数的形参,不仅要支付构造函数析构函数的执行代价,当遇上大对象时更是空间的极大浪费,还有就是对象做为形参是不能改变函数体外的数据的;如果用指针,效率问题可以得到问题,却要承担更大的风险,如空指针、野指针引发的内存泄漏或异常;还有不能有效防止函数体内不影响函数体个的数据,引用用const修饰保证常量性,用声明时初始化来保证非空。
2、安全:
主要与指针相比,原因在1中说明。
3、可以避免在某些情况禁止拷贝构造函数。
关于拷贝构造函数的具体介绍见调试经验中的详细说明。
b、对MFC的学习。
利用这次实验的机会,我在以前C++语言的基础上学习了windows环境下的编程,先是API,后来就是MFC了,可以在这次实验后,我已可以基本了解windows以及MFC的编程机制了。
C、对图形理论的更深入的理解。
毕竟,从理论到实践还有那么一段距离,可是当你跨过去之后,也是对理论学习的一种补充与提高。
更重要的是,就像郝老师说的:
编程到了一定程度上时又要求理论知识的良好掌握。
是的,两者相辅相成,缺一不可。
D、最后,要感谢我的图形老师郝建强老师,他不仅在理论上帮助了我,更从编程方面给了我许多有益的启发。
参考书:
1、《计算机图形学》倪明田、吴良芝编著,北京大学出版社
2、《MFCwindows程序设计》(第2版)JeffProsise清华大学出版社
3、《windows图形编程》FengYuan机械工业出版社
4、《C++编程思想》Bruck著侯捷译机械工业出版社