计算机图形学实验报告-实验1直线段扫描转换.doc
《计算机图形学实验报告-实验1直线段扫描转换.doc》由会员分享,可在线阅读,更多相关《计算机图形学实验报告-实验1直线段扫描转换.doc(9页珍藏版)》请在冰豆网上搜索。
计算机图形学
实验报告
班级计算机工硕班
学号2011220456
姓名王泽晶
实验一:
直线段扫描转换
实验目的
通过本次试验,学生可以掌握直线段的扫描转换算法及其程序设计方法。
实验内容
1.绘制20*20的网格线,格子X和Y方向间隔均为20像素,网格起始坐标在(20,20)。
我们使用此网格模拟像素矩阵(),格子交叉点是像素中心。
2.输入直线段两端点,可使用以下两种方法之一:
a)对话框输入
b)鼠标在网格内以鼠标左键按下-拖动-抬起方式输入。
注意:
直线段两端点要自动取整到模拟的像素中心位置
3.进行直线段扫描转换,通过点击鼠标右键调用方式或者菜单调用的方式执行。
计算完成后,将扫描转换结果,在模拟的像素矩阵中,使用圆形显示出来。
方法一:
直线的中点算法
算法的主要思想:
讨论斜率k∈[1,+∞)上的直线段的中点算法。
对直线,左下方的端点为(x0,y0),右上方的端点为(x1,y1)。
直线段的方程为:
现在假定已求得像素(),则如图得
由于直线的斜率k∈[1,+∞),故m=1/k∈(0,1],则
在直线上,区间内存在两个像素NE和E。
根据取整原则,当在中点M右方时,取像素NE,否则取像素E,即
若取,则上式变为
计算的递推公式如下:
=
算法的初始条件为:
相应的程序示例:
publicfunctiondrawLine(pixelDrawer:
Function,x0:
int,y0:
int,x1:
int,y1:
int):
void
{
vardx:
Number=x1-x0;
vardy:
Number=y1-y0;
varx:
Number;
vary:
Number;
if((dx==0)&&(dy==0))
{
//两点重合时,直接绘制重合的点
pixelDrawer(x0,y0);
return;
}
elseif(dx==0)
{
//第二点落在X轴上,直接绘制直线上的点
varstep:
Number=dy/Math.abs(dy);
for(y=y0;y!
=y1;y+=step)
pixelDrawer(x0,y);
}
elseif(dy==0)
{
//第二点落在Y轴上,直接绘制直线上的点
step=dx/Math.abs(dx);
for(x=x0;x!
=x1;x+=step)
pixelDrawer(x,y0);
}
varstepX:
Number=dx/Math.abs(dx);
varstepY:
Number=dy/Math.abs(dy);
x=x0,y=y0;
pixelDrawer(x,y);//绘制起点
vark:
Number=dy/dx;
if(Math.abs(k)<1.0)//斜率<1的情形,以X为自变量递增
{
vara:
Number=-Math.abs(dy);
varb:
Number=Math.abs(dx);
vard:
Number=2*a+b;
vard1:
Number=2*a;
vard2:
Number=2*(a+b);
while(x!
=x1)
{
if(d<0){x+=stepX;y+=stepY;d+=d2;}
else{x+=stepX;d+=d1;}
pixelDrawer(x,y);
}
}
else//斜率>=1的情形,以Y为自变量递增
{
a=-Math.abs(dx);
b=Math.abs(dy);
d=2*a+b,d1=2*a,d2=2*(a+b);
while(y!
=y1)
{
if(d<0){x+=stepX;y+=stepY;d+=d2;}
else{y+=stepY;d+=d1;}
pixelDrawer(x,y);
}
}
pixelDrawer(x1,y1);//绘制终点
}
编译运行程序得到如下结果:
方法二:
直线的数值微分法
算法的主要思想:
由于课本上已经给出了斜率m∈[-1,1]上的算法,故此处给出斜率m∈[1,+∞〕上的算法,m∈(-∞,-1]上的可同理推导。
已知待扫描转换的直线为(x0,y0),,又,则设k=1/m=(即k∈(0,1])。
直线方程为,即。
以一个像素为单位分割区间[y0,y1],由x0,….,其中=+1,得到点列,由公式
故从直接得到。
可能为浮点数,要对它取整,实际得到像素集。
初值为:
()=(x0,y0)。
实验内容:
编写自定义的算法类,程序:
publicfunctiondrawLine(pixelDrawer:
Function,x0:
int,y0:
int,x1:
int,y1:
int):
void
{
vardx:
int=x1-x0
vardy:
int=y1-y0;
if((dx==0)&&(dy==0))
{
//两点重合时,直接绘制重合的点
pixelDrawer(x0,y0);
return;
}
elseif(dx==0)
{
//第二点落在X轴上,直接绘制直线上的点
varstep:
int=dy/Math.abs(dy);
for(vary:
int=y0;y!
=y1;y+=step)
pixelDrawer(x0,y);
}
elseif(dy==0)
{
//第二点落在Y轴上,直接绘制直线上的点
step=dx/Math.abs(dx);
for(varx:
int=x0;x!
=x1;x+=step)
pixelDrawer(x,y0);
}
else
{
vark:
Number=dy/dx;
if(Math.abs(k)<1)//斜率<1的情形,以X为自变量递增
{
vary2:
Number=0.0;
y2=y0;
step=dx/Math.abs(dx);
for(x=x0;x!
=x1;x+=step)
{
pixelDrawer(x,int(y2+0.5));
y2=y2+k*step;
}
}
else//斜率>=1的情形,以Y为自变量递增
{
varx2:
Number=0.0;
varkInv:
Number=1.0/k;
x2=x0;
step=dy/Math.abs(dy);
for(y=y0;y!
=y1;y+=step)
{
pixelDrawer(int(x2+0.5),y);
x2=x2+kInv*step;
}
}
}
pixelDrawer(x1,y1);//绘制终点
}
编译运行程序得到如图所示结果:
方法三:
生成直线段的Bresenham算法
与中点算法类似,Bresenham算法也是通过在每列像素中确定与理想直线最近的像素来进行直线扫描转换的。
为了讨论方便,此处假定直线的斜率在0,1之间。
对直线对直线,左下方的端点为(x0,y0),右上方的端点为(x1,y1)。
如图,由到,则d=d+m,一旦d1时,d=d-1,以保证d始终在0,1之间。
初始条件为:
编写成员函数如下:
publicfunctiondrawLine(pixelDrawer:
Function,x0:
int,y0:
int,x1:
int,y1:
int):
void
{
vardx:
Number=x1-x0;
vardy:
Number=y1-y0;
varstep:
Number;
varx:
Number;
vary:
Number;
if((dx==0)&&(dy==0))
{
//两点重合时,直接绘制重合的点
pixelDrawer(x0,y0);
return;
}
elseif((dx==0))
{
//第二点落在X轴上,直接绘制直线上的点
step=dy/Math.abs(dy);
for(y=y0;y!
=y1;y+=step)
pixelDrawer(x0,y);
}
elseif((dy==0))
{
//第二点落在Y轴上,直接绘制直线上的点
step=dx/Math.abs(dx);
for(x=x0;x!
=x1;x+=step)pixelDrawer(x,y0);
}
varabsDX:
Number=Math.abs(dx);
varabsDY:
Number=Math.abs(dy);
varstepX:
Number=dx/absDX;
varstepY:
Number=dy/absDY;
vark:
Number=dy/dx;
if(Math.abs(k)<1.0)//斜率<1的情形,以X为自变量递增
{
vare:
Number=-absDX;
x=x0;
y=y0;
for(vari:
Number=0;i!
=dx;i+=stepX)
{
pixelDrawer(x,y);
x+=stepX;
e+=2*absDY;
if(e>=0)
{
y+=stepY;
e-=2*absDX;
}
}
}
else//斜率>=1的情形,以Y为自变量递增
{
e=-absDY;
x=x0;
y=y0;
for(i=0;i!
=dy;i+=stepY)
{
pixelDrawer(x,y);
y+=stepY;e+=