计算机图形学实验一Word文档下载推荐.docx
《计算机图形学实验一Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验一Word文档下载推荐.docx(19页珍藏版)》请在冰豆网上搜索。
ID_DDALINE
Bresenham算法生成直线
ID_BRESENHAMLINE
中点算法生成直线
ID_MIDPOINTLINE
4.添加消息处理函数
利用ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CMyView,根据表1-2建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表1-2菜单项的消息处理函数
菜单项ID
消息
消息处理函数
CONMMAN
OnDdaline
OnMidpointline
OnBresenhamline
5.程序结构代码,在CMyView.cpp文件中相应位置添加如下代码:
//DDA算法生成直线
voidCMyView:
:
OnDdaline()
{
CDC*pDC=GetDC();
//获得设备指针
intxa=100,ya=300,xb=300,yb=200,c=RGB(255,0,0);
//定义直线的两端点,直线颜色
intx,y;
floatdx,dy,k;
dx=(float)(xb-xa),dy=(float)(yb-ya);
k=dy/dx,y=ya;
if(abs(k)<
1)
{
for(x=xa;
x<
=xb;
x++)
{pDC->
SetPixel(x,int(y+0.5),c);
y=y+k;
}
}
if(abs(k)>
=1)
for(y=ya;
y<
=yb;
y++)
SetPixel(int(x+0.5),y,c);
x=x+1/k;
}
ReleaseDC(pDC);
说明:
(1)以上代码理论上通过定义直线的两端点,可得到任意端点之间的一直线,但由于一般屏幕坐标采用右手系坐标,屏幕上只有正的x,y值,屏幕坐标与窗口坐标之间转换知识请参考第3章。
(2)注意上述程序考虑到当k?
1的情形x每增加1,y最多增加1;
当k>
1时,y每增加1,x相应增加1/k。
在这个算法中,y与k用浮点数表示,而且每一步都要对y进行四舍五入后取整。
//中点算法生成直线
OnMidpointline()
intxa=300,ya=200,xb=450,yb=300,c=RGB(0,255,0);
floata,b,d1,d2,d,x,y;
a=ya-yb,b=xb-xa,d=2*a+b;
d1=2*a,d2=2*(a+b);
x=xa,y=ya;
pDC->
SetPixel(x,y,c);
while(x<
xb)
{if(d<
0){x++,y++,d+=d2;
else{x++,d+=d1;
ReleaseDC(pDC);
(1)其中d是xp,yp的线性函数。
为了提高运算效率,程序中采用增量计算。
具体算法如下:
若当前像素处于d>
0情况,则取正右方像素P1(xp+1,yp),判断下一个像素点的位置,应计算d1=F(xp+2,yp+0.5)=a(xp+2)+b(yp+0.5)=d+a;
,其中增量为a。
若d<
0时,则取右上方像素P2(xp+1,yp+1)。
再判断下一像素,则要计算d2?
=F(xp+2,yp+1.5)=a(xp+2)+b(yp+1.5)?
+?
c=d+a+b,增量为a+b。
(2)画线从(x0,y0)开始,d的初值d0=F(x0+1,y0+0.5)=F(x0,y0)+a+0.5b,因F(x0,y0)=0,则d0=a+0.5b。
(3)程序中只利用d的符号,d的增量都是整数,只是初始值包含小数,用2d代替d,使程序中仅包含整数的运算。
//Bresenham算法生成直线
voidCMyView:
OnBresenhamline()
intx1=100,y1=200,x2=350,y2=100,c=RGB(0,0,255);
inti,s1,s2,interchange;
floatx,y,deltax,deltay,f,temp;
x=x1;
y=y1;
deltax=abs(x2-x1);
deltay=abs(y2-y1);
if(x2-x1>
=0)s1=1;
elses1=-1;
if(y2-y1>
=0)s2=1;
elses2=-1;
if(deltay>
deltax){
temp=deltax;
deltax=deltay;
deltay=temp;
interchange=1;
elseinterchange=0;
f=2*deltay-deltax;
SetPixel(x,y,c);
for(i=1;
i<
=deltax;
i++){
if(f>
=0){
if(interchange==1)x+=s1;
elsey+=s2;
pDC->
f=f-2*deltax;
}
else{
if(interchange==1)y+=s2;
elsex+=s1;
f=f+2*deltay;
(1)以上程序已经考虑到所有象限直线的生成。
(2)Bresenham算法的优点如下:
①不必计算直线的斜率,因此不做除法。
②不用浮点数,只用整数。
③只做整数加减运算和乘2运算,而乘2运算可以用移位操作实现。
④Bresenham算法的运算速度很快。
圆弧生成程序设计的步骤如下:
(1)创建应用程序框架,以上面建立的单文档程序框架为基础。
(2)编辑菜单资源。
在工作区的ResourceView标签中,单击Menu项左边“+”,然后双击其子项IDR_MAINFRAME,并根据表1-3中的定义添加编辑菜单资源。
此时建好的菜单如图1-3所示。
图1-3程序主菜单
表1-3菜单资源表
圆
中点画圆
ID_MIDPOINTCIRCLE
Bresenham画圆
ID_BRESENHAMCIRCLE
(3)添加消息处理函数。
利用ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CMyView,根据表1-4建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表1-4菜单项的消息处理函数
OnMidpointcircle
OnBresenhamcircle
(4)程序结构代码,在CMyView.cpp文件中的相应位置添加如下代码。
OnMidpointcircle()//中点算法绘制圆,如图1-4所示
图1-4中点算法绘制圆
//TODO:
Addyourcommandhandlercodehere
intxc=300,yc=300,r=50,c=0;
floatd;
x=0;
y=r;
d=1.25-r;
SetPixel((xc+x),(yc+y),c);
SetPixel((xc-x),(yc+y),c);
SetPixel((xc+x),(yc-y),c);
SetPixel((xc-x),(yc-y),c);
SetPixel((xc+y),(yc+x),c);
SetPixel((xc-y),(yc+x),c);
SetPixel((xc+y),(yc-x),c);
SetPixel((xc-y),(yc-x),c);
while(x<
=y)
{if(d<
0)d+=2*x+3;
else{d+=2*(x-y)+5;
y--;
x++;
OnBresenhamcircle()////Bresenham算法绘制圆,如图1-5所示
intxc=100,yc=100,radius=50,c=0;
图1-5Bresenham算法绘制圆
intx=0,y=radius,p=3-2*radius;
while(x<
y)
pDC->
SetPixel(xc+x,yc+y,c);
SetPixel(xc-x,yc+y,c);
SetPixel(xc+x,yc-y,c);
SetPixel(xc-x,yc-y,c);
SetPixel(xc+y,yc+x,c);
SetPixel(xc-y,yc+x,c);
SetPixel(xc+y,yc-x,c);
SetPixel(xc-y,yc-x,c);
if(p<
0)
p=p+4*x+6;
else
p=p+4*(x-y)+10;
y-=1;
}
x+=1;
if(x==y)
多边形填充程序设计的步骤如下:
(1)创建应用程序框架,以上述单文档程序框架为基础,创建如图1-17所示应用程序界面。
在工作区的ResourceView标签中,单击Menu项左边“+”,然后双击其子项IDR_MAINFRAME,并根据表1-7中的定义添加编辑菜单资源。
此时建好的菜单如图1-18所示。
图1-17程序界面
表1-7菜单资源表
区域填充
多边形扫描填充
ID_SCANFILL
种子填充
ID_SEEDFILL
图1-18程序主菜单
利用ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CMyView,根据表1-8建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表1-8菜单项的消息处理函数
OnScanfill
OnSeedfill
(4)添加程序结构代码。
①在“基本图形的生成View.h”适当位置添加以下黑体字部分代码:
typedefstruct//建立边表结构
intnum,ymin,ymax;
floatxmin,xmax,dx;
}Edge;
classCMyView:
publicCView
protected:
//createfromserializationonly
public:
Cpointptset[7];
Edgeedge[7],edge1[7],newedge[1];
②在OnDraw()函数中添加如下黑体字部分代码。
OnDraw(CDC*pDC)//绘制要填充的多边形
CMyDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
CPennewpen(PS_SOLID,1,RGB(255,0,0));
CPen*old=pDC->
SelectObject(&
newpen);
TextOut(20,20,"
双击鼠标左键,出现需填充的多边形,点击相关功能菜单实现区域填充"
);
TextOut(20,50,"
进行种子填充,需用鼠标右键,单击多边形内一点,作为开始填充的种子点"
SelectObject(old);
③在菜单项的消息处理函数实体中添加以下黑体字部分代码。
OnScanfill()//扫描线算法进行多边形区域填充,如图1-19所示
CPennewpen(PS_SOLID,1,RGB(0,255,0));
CPen*old=pDC->
intj,k,s=0;
图1-19扫描线算法区域填充
intp[5];
//每根扫描线交点
intpmin,pmax;
for(inti=0;
6;
i++)//建立边表
edge[i].dx=(float)(spt[i+1].x-spt[i].
x)/(spt[i+1].y-spt[i].y);
if(spt[i].y<
=spt[i+1].y){
edge[i].num=i;
edge[i].ymin=spt[i].y;
edge[i].ymax=spt[i+1].y;
edge[i].xmin=(float)spt[i].x;
edge[i].xmax=(float)spt[i+1].x;
pmax=spt[i+1].y;
pmin=spt[i].y;
else{
edge[i].ymin=spt[i+1].y;
edge[i].ymax=spt[i].y;
edge[i].xmax=(float)spt[i].x;
edge[i].xmin=(float)spt[i+1].x;
pmax=spt[i].y;
pmin=spt[i+1].y;
}
for(intr=1;
r<
r++)//排序edge(yUpper,xIntersect)
for(intq=0;
q<
6-r;
q++)
{
if(edge[q].ymin<
edge[q+1].ymin)
{
newedge[0]=edge[q];
edge[q]=edge[q+1];
edge[q+1]=newedge[0];
}
for(intscan=pmax-1;
scan>
pmin+1;
scan--)
intb=0;
k=s;
for(j=k;
j<
j++)
{
if((scan>
edge[j].ymin)&
&
(scan<
=edge[j].ymax))//判断与线段相交
if(scan==edge[j].ymax)
{
if(spt[edge[j].num+1].y<
edge[j].ymax)
{
b++;
p[b]=(int)edge[j].xmax;
}
if(spt[edge[j].num-1].y<
b++;
}
}
if((scan>
edge[j].ymax))
b++;
p[b]=(int)(edge[j].xmax+edge[j].dx*(scan-edge[j].
ymax));
}
//pDC->
LineTo(spt[edge[0].num].x,spt[edge[0].num].y);
if(scan<
=edge[j].ymin)//
s=j;
}
if(b>
{
for(intu=1;
u<
b;
u++)
MoveTo(p[u]+3,scan);
u++;
LineTo(p[u],scan);
双击,出现需填充的多边形,单击相关功能菜单实现区域填充。
OnSeedfill()//种子算法进行多边形区域填充,如图1-20所示
CWindowDCdc(this);
intfill=RGB(0,255,0);
图1-20种子算法区域填充
intboundary=RGB(255,0,0);
CPointpt=s_point;
intx,y,p0,pmin,pmax;
//求多边形的最大最小值
for(intm=1;
m<
7;
m++)
for(intn=0;
n<
7-m;
n++)
if(spt[n].y<
spt[n+1].y)
p0=spt[n].y;
spt[n]=spt[n+1];
spt[n+1]=p0;
pmax=spt[0].y,pmin=spt[6].y;
x=s_point.x;
y=s_point.y;
for(;
pmax+1;
y++)
intcurrent=dc.GetPixel(x,y);
while((current!
=boundary)&
(current!
=fill))
{
dc.SetPixel(x,y,fill);
x++;
current=dc.GetPixel(x,y);
}
x=s_point.x;
x--;
x--;
x=s_point.x;
y=s_point.y-1;
y>
pmin-2;
y--)
while((current!