计算机图形学实验报告Word文档格式.docx
- 文档编号:17508297
- 上传时间:2022-12-06
- 格式:DOCX
- 页数:45
- 大小:320.94KB
计算机图形学实验报告Word文档格式.docx
《计算机图形学实验报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验报告Word文档格式.docx(45页珍藏版)》请在冰豆网上搜索。
编程语言:
C++
IDE版本:
MicrosoftVisualC++6.0
实验方法:
使用MFC进行编程,参照实验指导书,一步一步操作,就可以基本完成整个实验的操作了。
1、建立程序框架:
创建MFC单文档应用程序
2、添加绘图菜单项
通过更改各个菜单选项属性,设置好ID号,并标明,如图所示
3、在创建的View中添加个消息函数
添加对应消息WM_CREAT的消息函数OnCreate()函数
添加对应鼠标消息的WM_LBUTTONDOWN的消息函数OnLButtonDown();
添加对应鼠标消息的WM_MOUSEMOVE的消息函数OnMouseMove();
添加对应鼠标消息的WM_RBUTTONDOWN的消息函数OnRButtonDown();
添加对应鼠标消息的WM_MOUSEWHEEL的消息函数OnMouseWheel();
4、声明变量和函数
5、添加各菜单项的消息映射函数
主要添加的响应有,鼠标右键、鼠标右键、鼠标滑轮、鼠标移动、键盘按键响应。
每个工程的建立大同小异,下面将不对工程的建立和设置进行描述和说明。
主要讨论程序的算法和实现。
具体的设置参见程序。
基本图元
一、实验内容
本实验程序实现的主要函数及其说明
关于绘制图形的算法的函数:
voidDDALine(CPointstart,CPointend,longcolor);
//用DDA算法绘制直线
voidMiddleLine(CPointstart,CPointend,longcolor);
//用中点算法绘制直线
voidBresenhamLine(CPointstart,CPointend,longcolor);
//用Bresenham算法绘制直线
voidRectangle(CPointstart,CPointend,longcolor);
//绘制多边形
voidBresenhamCircle(CPointcenter,CPointt,longcolor);
//用Bresenham算法绘制圆
voidMiddleCircle(CPointcenter,CPointt,longcolor);
//用中点算法绘制圆
voidMiddleEllipse(CPointstart,CPointend,longcolor);
//用中点算法绘制椭圆
二、程序设计说明及源代码:
1、绘制直线的算法
1)、DDA算法
解:
这个算法代码是直接抄写实验书上面的呀,算法比较明显,通过计算x方向和y方向的增量依次画出各个点,而这个代码也写得比较精炼step的应用大大减少代码量。
代码如下:
voidCExercise1View:
:
DDALine(CPointstart,CPointend,longcolor)
{
CClientDCdc(this);
dc.SetPixel(start.x,start.y,color);
dc.SetPixel(end.x,end.y,color);
//dx和dy分别是x方向和y方向的增量
intdx=end.x-start.x,dy=end.y-start.y,steps,k;
floatxIncrement,yIncrement,x=start.x,y=start.y;
//选择增量大的方向作为每次前进的方向
if(fabs(dx)>
fabs(dy))steps=fabs(dx);
elsesteps=fabs(dy);
//计算每个方向的前进增量
xIncrement=float(dx)/float(steps);
yIncrement=float(dy)/float(steps);
dc.SetPixel((int)(x+0.5),(int)(y+0.5),color);
for(k=0;
k<
steps;
k++)//根据增量进行画点
{
x+=xIncrement;
y+=yIncrement;
dc.SetPixel((int)(x+0.5),(int)(y+0.5),color);
}
}
2)、中点算法
通过计算中点在直线的上方还是下方来决定选择点直线方程
当斜率在
时,
,这时考虑右上方和右下方的点:
时,取右下方的点,此时判别式为:
,这时考虑上左方和上右方的点:
时,取上左方的点,此时判别式为:
时,取上右方的点,此时判别式为:
斜率在
和
的情况类似上面的推导,这里就不进行推导。
代码考虑了斜率的所有情况。
MiddleLine(CPointstart,CPointend,longcolor)
CPointTempPoint;
if(start.x>
end.x){TempPoint=start;
start=end;
end=TempPoint;
inta,b,d1,d2,d,x,y,flag=0,temp;
if(fabs(start.x-end.x)>
fabs(start.y-end.y))flag=1;
x=start.x;
y=start.y;
dc.SetPixel(x,y,color);
a=start.y-end.y;
b=end.x-start.x;
if(start.y>
end.y)b=-b;
if(flag==0){temp=a;
a=b;
b=temp;
d=2*a+b;
d1=2*a;
d2=2*(a+b);
if(start.y<
=end.y)
if(flag==1){
while(x<
end.x)
if(d<
0){x++;
y++;
d+=d2;
else{x++;
d+=d1;
dc.SetPixel(x,y,color);
}
}else{
while(y<
end.y)
if(d>
0){y++;
x++;
else{y++;
}
else
end.x)
y--;
while(y>
end.y){
0){y--;
else{y--;
3)、Bresenham算法
这个算法参照实验指导书只考虑斜率在
的情况,进行扩展,其实很简单,只要将x和y的位置交换下就可以了,再根据x和y的前进方向进行设置就可以了,程序很容易写完。
BresenhamLine(CPointstart,CPointend,longcolor)
intdx=fabs(end.x-start.x),dy=fabs(end.y-start.y);
intd,twoDy,twoDyMinusDx;
intx,y,t=1,count;
end.y)t=-1;
y=start.y;
if(dx>
=dy)
d=2*dy-dx;
twoDy=2*dy,twoDyMinusDx=2*(dy-dx);
while(x<
{
x++;
if(d<
0)d+=twoDy;
else{y+=t;
d+=twoDyMinusDx;
dc.SetPixel(x,y,color);
else
d=2*dx-dy;
twoDy=2*dx,twoDyMinusDx=2*(dx-dy);
count=0;
while(count<
dy)
count++;
y+=t;
else{x++;
2、多边形绘制
1)、三角形
三角形画法很简单只是用鼠标点三个点,然后将三个点连线就可以了。
这个难点在于交与方面和实现橡皮筋功能方面。
2)、矩形
矩形的画法也比教简单,只是选择两个点(XA,YA),(XB,XY),然后组合后画出对应的4条线段就可以了。
3)、多边形
通过鼠标点击的点依次画出各个点间的连线就可以了,最后结束的时候只要点击鼠标右键就可以了。
3、圆的绘制算法
1)、中点算法
这个算法的原理和直线的中点算法原理一样,代码完全参照课本给的程序,修改下就可以使用了,也结合了实验指导书的例程。
MiddleCircle(CPointcenter,CPointt,longcolor)
CPointtemp;
floatradius=sqrt((center.x-t.x)*(center.x-t.x)+(center.y-t.y)*(center.y-t.y));
intp=1-(int)radius;
temp.x=(int)radius;
temp.y=0;
circlePlotPoint(center,temp,color);
while(temp.y<
temp.x)
temp.y++;
if(p<
0)p+=2*temp.y+3;
else{temp.x--;
p+=2*(temp.y-temp.x)+5;
circlePlotPoint(center,temp,color);
2)、Bresenham算法
也是参照书上的例程,修改下,对这个算法的理解还不是很深刻。
BresenhamCircle(CPointcenter,CPointt,longcolor)
intR=(int)sqrt((center.x-t.x)*(center.x-t.x)+(center.y-t.y)*(center.y-t.y));
intd=3-2*R;
temp.x=0;
temp.y=R;
while(temp.x<
temp.y)
if(d<
0)d=d+4*temp.x+6;
else{d=d+4*(temp.x-temp.y)+10;
temp.y--;
temp.x++;
if(temp.x==temp.y)circlePlotPoint(center,temp,color);
4、椭圆绘制算法
首先将椭圆分成两个区域,以切线斜率为-1作为分界。
由
及
算出分界点
,
初值为
,从(0,b)开始画到(x,y)到(a,0)
切线斜率
当
,当
代码如下:
MiddleEllipse(CPointstart,CPointend,longcolor)
CPointt,k;
temp=start;
inta=fabs(start.x-end.x),b=fabs(start.y-end.y);
if(a==0||b==0)return;
intaa=a*a,bb=b*b;
k.x=(int)((float)aa/sqrt((float)(aa+bb))+0.5);
k.y=(int)((float)aa/sqrt((float)(aa+bb))+0.5);
t.x=0;
t.y=b;
intd=4*(bb-aa*b)+aa;
ellipsePlotPoint(temp,t,color);
while(t.x<
=k.x)
0)d+=4*bb*(2*t.x+3);
else{d+=4*(bb*(2*t.x+3)+2*aa*(1-t.y));
t.y--;
t.x++;
ellipsePlotPoint(temp,t,color);
while(t.y>
0)
if(d>
=0)d+=4*aa*(3-2*t.y);
else{d+=4*((2*bb*(t.x+1))+aa*(3-2*t.y));
t.x++;
t.y--;
区域填充
voidLineFill();
//用扫描线算法填充多边形
voidSideNotFill();
//用边取反算法填充多边形
voidSeedFill(CPointtemp);
//用种子填充算法填充区域
voidLineSeedFill(CPointseed);
//用扫描线种子填充算法填充区域
1、多边形填充算法
1)、扫描线填充算法
用到的数据结构:
桶ET和边的活性边表AEL
算法的描述如下:
for(y=ymin;
i<
=ymax;
y++)
合并当前扫描线y的ET表;
将y桶中的每个记录按x项升序排列;
在当前y值下,将两两记录的x值之间的像素进行填充;
修改边记录x=x+1/m;
(m为直线斜率的倒数)
这个算法主要的函数有
buildEdgelist(cnt,pts,edges);
//建立边表
buildActivelist(scan,active,edges);
//建立活性边
fillscan(scan,active);
//填充
updateActivelist(scan,active);
//更新
resortActivelist(active);
//重排序
2)、边取反填充算法
对图像M作偶数次取反运算后还是M,而对图像作奇数次取反后的结果是~M,可以利用这个原理对多边形的每一条边向右填充逐位取反操作。
算法比较简单,但是要注意一点就是顶点的处理,顶点分为内点和外点。
对于每一个顶点,如果他相邻的两个顶点在它的同一侧,则这个点为外点,否则称为内点。
对于内点只需要向右填充一次,外点不需要向右进行填充。
为了增加向右填充的效率,在实验中先找出最右边的点,只需要填充到最右的这个点就可以了。
程序的代码如下:
voidCLabView:
SideNotFill()
CLabDoc*pdoc=GetDocument();
longi,n=pdoc->
NodeCount;
memset(pdoc->
PolygonNodeJudge,0,100*sizeof(pdoc->
PolygonNodeJudge[0]));
moreLeft=pdoc->
PolygonNode[0].x;
//判断第0个点是内点还是外点
if((pdoc->
PolygonNode[n-1].y>
pdoc->
PolygonNode[0].y&
&
pdoc->
PolygonNode[1].y<
PolygonNode[0].y)||
(pdoc->
PolygonNode[n-1].y<
PolygonNode[1].y>
PolygonNode[0].y)){
pdoc->
PolygonNodeJudge[0]=1;
//判断最后一个点是内点还是外点
if((pdoc->
PolygonNode[0].y>
PolygonNode[n-1].y&
PolygonNode[n-2].y<
PolygonNode[n-1].y)||
(pdoc->
PolygonNode[0].y<
PolygonNode[n-2].y>
PolygonNode[n-1].y)){
PolygonNodeJudge[n-1]=1;
//对其他点进行判断是内点还是外点
for(i=1;
n-1;
i++){
if((pdoc->
PolygonNode[i-1].y>
PolygonNode[i].y&
PolygonNode[i+1].y<
PolygonNode[i].y)||
PolygonNode[i-1].y<
PolygonNode[i+1].y>
PolygonNode[i].y)){
pdoc->
PolygonNodeJudge[i]=1;
//找出多边形中“最右”的那个点的y值
i++)
if(pdoc->
PolygonNode[i].x>
moreLeft)moreLeft=pdoc->
PolygonNode[i].x;
moreLeft=moreLeft+10>
m_rect.right?
m_rect.right:
moreLeft+10;
if(pdoc->
PolygonNode[0].y!
=pdoc->
PolygonNode[pdoc->
NodeCount-1].y)
LineDDA2(pdoc->
PolygonNodeJudge[0],pdoc->
PolygonNode[0],pdoc->
NodeCount-1],pdoc->
PenColor);
PolygonNode[i].y!
PolygonNode[i-1].y)
PolygonNodeJudge[i],pdoc->
PolygonNode[i],pdoc->
PolygonNode[i-1],pdoc->
2、区域填充算法
1)、扫描线种子填充算法
扫描线种子填充算法的基本思想是:
从给定的种子开始,填充当前扫描线上种子点所在的区间,然后确定与这一区间相邻的上下两条扫描线上需要填充的区间,从这些区间上各取一个点并依次保存下来,作为下次填充的种子点,反复进行,到填充完这个区间为止。
这个算法是参考课本的扫描线种子填充算法,经过补充和修改而成的。
核心代码如下:
LineSeedFill(CPointseed)
CPointstack[1024],t;
longslen=0,savex,xright,xleft,flag;
unsignedlongcolor=dc.GetPixel(seed);
//如果填充的区域的颜色与要填充的颜色一样,则要退出
if(color==pdoc->
FillColor)return;
stack[slen++]=seed;
//将种子放进栈中
w
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 图形学 实验 报告