计算机图形学实验报告Word文档格式.docx

上传人:b****5 文档编号:17508297 上传时间:2022-12-06 格式:DOCX 页数:45 大小:320.94KB
下载 相关 举报
计算机图形学实验报告Word文档格式.docx_第1页
第1页 / 共45页
计算机图形学实验报告Word文档格式.docx_第2页
第2页 / 共45页
计算机图形学实验报告Word文档格式.docx_第3页
第3页 / 共45页
计算机图形学实验报告Word文档格式.docx_第4页
第4页 / 共45页
计算机图形学实验报告Word文档格式.docx_第5页
第5页 / 共45页
点击查看更多>>
下载资源
资源描述

计算机图形学实验报告Word文档格式.docx

《计算机图形学实验报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验报告Word文档格式.docx(45页珍藏版)》请在冰豆网上搜索。

计算机图形学实验报告Word文档格式.docx

编程语言:

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > IT认证

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1