习题解答
第 2 章
2.如果线段端点坐标值不是整数,采用 DDA 算法产生的直线和将端点坐标值先取整
再用 Bresenham 算法产生的直线是否完全相同?为什么?能否扩充整数 Bresenham 算法使之能
处理当线段端点坐标值不是整数的情况(比端点坐标先取整数产生的直线更精确)。
如果线段端点坐标值不是整数,DDA 算法和 Bresenham 算法产生的直线不完全相同。
DDA 算法是在直线附近寻找最靠近直线的象素点。而端点坐标值先取整再用 Bresenham 算
法,因为端点坐标值先取整,与原直线相比,可能会改变直线的斜率。因此两种算法相比,
前者比后者更精确。
可以将整数 Bresenham 算法扩充为实数 Bresenham 算法。算法中的变量都应采用实数类
型,在绘制时再对实数坐标值取整数,这样做比端点坐标先取整数产生的直线更精确,具体
算法如下:
void BresenhamLine(double x1, double y1, double x2, double y2)
{
int x,y ;
double dx,dy,p;
x=(int)(x1+0.5);
y=(int)(y1+0.5);
dx=x2-x1;
dy=y2-y1;
p=2*dy*(x-x1+1)-dx*(2*y-2*y1+1);
for(;x<=x2;x++)
{
SetPixel(x,y);
if(p>=0)
{
y++;
p+=2*(dy-dx);
}
else
{
}
p+=2*dy;
}
}
3.推广本章第一节给出的产生线段的整数 Bresenham 算法,去掉 0≤m≤1 和 xl
dy
dx
y
d
1
(
x
b y
x
)
y
d
2
(
dx d
p
1
i
(
2
dy x
p
1
i
2
dy x
p
(
x
dy
dx
2
)
(
d
dy x
2
2
) 2(
x
2(
y
i
1
)
x
b
ydx
b y dx
)
i
ydx
) 2(
x
)
b y
dx
i
)
y dx
i
1
若
ip , 则 1iy
0
,
y
y
p
2
dy x
2
dx y
; 若
ip , 则 1
iy
0
,
0
y
p
2
dy x
。
m
0≤m≤1
Δx Δy Δp(p≥0)
>0 >0
2
dy
p
2
dx
Δp(p<0)
2
p
dy
<0 <0
p
2
dy
2
dx
p
2
dy
-1≤m≤0 >0 <0
p
2
dy
2
dx
p
2
dy
<0 >0
p
2
dy
2
dx
p
2
dy
m>1
>0 >0
p
2
dx
2
dy
p
2
dx
<0 <0
p
2
dx
2
dy
p
2
dx
m<-1
>0 <0
p
2
dx
2
dy
p
2
dx
<0 >0
p
2
dx
2
dy
p
2
dx
void BresenhamLine(int x1,int y1,int x2,int y2)
{
int x,y,dx,dy,p,xmin,ymin,xmax,ymax,lx,ly,deltax,deltay;
dx=x2-x1;
dy=y2-y1;
xmin=min(x1,x2);
xmax=max(x1,x2);
ymin=min(y1,y2);
ymax=max(y1,y2);
lx=xmax-xmin;
ly=ymax-ymin;
deltax= (dx==0)?0:(dx>0?1:-1);
deltay= (dy==0)?0:(dy>0?1:-1);
x=x1;
y=y1;
if(lx>ly)
{
p=2*dy-dx;
for(;x!=x2;x+=deltax)
{
SetPixel(x,y,RGB(0,0,0));
if(p>=0)
{
y+=deltay;
p+=2*(ly-lx);
}
else
{
}
p+=2*ly;
}
}
else
{
p=2*dx-dy;
for(;y!=y2;y+=deltay)
{
SetPixel(x,y,RGB(0,0,0));
if(p>=0)
{
x+=deltax;
p+=2*(lx-ly);
}
else
{
}
p+=2*lx;
}
}
}
4.在本章第一节说明 Bresenham 算法如何选择下一个象素点位置的图 2.3 中,其实是
假定了在当前选择的点是(x,y)时,真正直线与横坐标为 x+1 的直线的交点是在 y 到 y+1 之
间。如果不是这样,而是下面两种情况:
(1)在 y 到 y-1 之间。例如从(0,0)到(7,2)的直线,在点(2,1)处向后。
(2)在 y+1 到 y+2 之间,例如从(0,0)到(7,5)的直线,在点(2,1)处向后。
试说明为什么对所列两种情况算法仍能正确地工作。
假定 0≤m≤1,如图所示
d1
d1
d2
d2
(x,y)
若当前象素点是(x,y),则该直线与横坐标为 x 的直线的交点必落在(x,y-0.5),(x,y+0.5)
之间。又由于 0≤m≤1,则该直线与横坐标为 x+1 的直线的交点必落在(x+1,y-0.5),(x+1,y+1.5)
之间。
情况(1),交点在 y-0.5 到 y 之间,d1<0,d2>0,则Δ=Δx (d1-d2)<0,应取(x+1,y);
情况(2),交点在 y+1 到 y+1.5 之间,d1>0,d2<0,则Δ=Δx (d1-d2)>0,应取(x+1,y+1。
以上结果是根据算法而得到的,同时该结果也符合实际的绘制。
综上,当交点在在 y-0.5 到 y 之间,四舍五入取象素点(x+1,y);当交点在在 y+1 到 y+1.5
之间,四舍五入取象素点(x+1,y+1)。
5.本章介绍的 Bresenham 直线算法是否可以利用对称性,通过判别量 p 同时从直线两
端向中心画线?当 0<Δy<Δx,Δx 和Δy 有最大公因数 c,而且Δx/c 为偶数和Δy/c 为奇
数时,两种方法画出的线是否一致?当Δx 是 2Δy 的整数倍时两种方法画出的线是否一致。
x y ,已知一点坐
求对称点的推导:设中点坐标为 (
)
)
)
y ,端点坐标为 1
m
,
x y 和 2
(
(
,
x
m
,
1
2
x
标为 1
i
(
,
y ,其对称点坐标为 2
x
1
i
)
(
,
y
i
2
i
)
x
m
x
2
i
(
x
x
1
x
x
1
2
) / 2 (
x
2
1
i
y
x
1
i
2
i
i
x
2
y
1
) / 2
y
2
y
m
y
1
i
(
y
1
y
2
) / 2 (
y
1
i
y
2
i
) / 2
void SymmetryBresenhamLine(int x1,int y1,int x2,int y2)
{
int x,y,dx,dy,p,xmin,ymin,xmax,ymax;
xmin=min(x1,x2);
xmax=max(x1,x2);
ymin=min(y1,y2);
ymax=max(y1,y2);
x=xmin;
y=ymin;
dx=xmax-xmin;
dy=ymax-ymin;
if(dx>dy)
{
p=2*dy-dx;
for(;(x+x)<=(xmin+xmax);x++)
{
SetPixel(x,y,RGB(0,0,0));
SetPixel((xmin+xmax)-x,(ymin+ymax)-y,RGB(0,0,0));
if(p>=0)
{
y++;
p+=2*(dy-dx);
}
else
{
}
p+=2*dy;
}
}
else
{
p=2*dx-dy;
for(;(y+y)<=(ymin+ymax);y++)
{
SetPixel(x,y,RGB(0,0,0));
SetPixel((xmin+xmax)-x,(ymin+ymax)-y,RGB(0,0,0));
if(p>=0)
{
x++;
p+=2*(dx-dy);
}
else
{
}
p+=2*dx;
}
}
}
当Δx 和Δy 有最大公因数 c,而且Δx/c 为偶数和Δy/c 为奇数时,和当Δx 是 2Δy
的整数倍时,对称性算法画出的线与 Bresenham 直线算法画出的线不一致。
例如:端点为(0,0)和(4,3)的线段(Δx/c 为偶数和Δy/c 为奇数)
用 Bresenham 直线算法画线
(0,0)(1,1)(2,2)(3,2)(4,3)
用对称性算法画线
(0,0)(4,3)(1,1)(3,2)(2,2)(2,1)
端点为(0,0)和(6,3)的线段(Δx 是 2Δy 的整数倍)
用 Bresenham 直线算法画线
(0,0)(1,1)(2,1)(3,2)(4,2)(5,3)(6,3)
用对称性算法画线
(0,0)(6,3)(1,1)(5,2)(2,1)(4,2)(3,2)(3,1)
6.推广本章第二节给出的 Bresenham 画圆算法使能够画出一个内部填充的实心圆。
填充实心圆算法
y
y=-x
y=x
x
void SolidBresenhamCircle(int x0,int y0,int R,COLORREF color)
{
int x,y,p,i;
x=0;
y=R;
p=3-2*R;
for(;x<=y;x++)
{
for(i=-x;i<=x;i++)
{
SetPixel(x0+i,y0+y,color);
SetPixel(x0+i,y0-y,color);
}
for(i=-y;i<=y;i++)
{
SetPixel(x0+i,y0+x,color);
SetPixel(x0+i,y0-x,color);
}
if(p>=0)
{
p+=4*(x-y)+10;
y--;
}
else
{
}
p+=4*x+6;