圆的Bresenham四分画法,其基本思想和直线的Bresenham画法是一样的,由当前点推断出下一个点的位置,一个点一个点地生成。同时,由于圆的的对称性,我们只需要计算出第一象限中的14圆就行了,其他三个象限的圆能通过对称性直接得到。具体做法如下:
假设目前所要画的点全部在以圆心为原点的直角坐标系中的第一象限。
如上图所示,假设我们当前点是 ,则下一个将要画出的点就一定是H(x+1,y)V(x,y−1)D(x+1,y−1)之一,现在的任务就是要判断这三个点中要去哪一个。其逻辑关系为:
If D在圆上,则选择D为一下个点
Else if D 在圆内,则选取D、H两者间最靠近圆的点
Else if D 在园外,则选取V、D两之间最靠近圆的点
其具体过程如下:
1、构造判别式
像画直线一样,我首先需要构造一个计算点到圆上的距离的判别式:F(x,y)=x2+y2−R2(我们把圆心看做坐标原点)
若F(x,y)>0,则 在圆外
若F(x,y)<0,则 在园内
若F(x,y)=0,则 在园上
2、计算判别式
当前点为p(x,y),则我们首先需要判断的是,D点在不在圆上,计算D点到圆的距离:ΔD=F(x+1,y−1)=(x+1)2+(y−1)2−R2
ΔD=0 选取D作为下一个点
ΔD<0 比较H、D哪个更加接近于圆:ΔDH=|ΔH|−|ΔD|=ΔH+ΔD=2(ΔD+y)−1
若ΔDH>0,选取D,若ΔDH<0,选取H
ΔD>0 比较V、D哪个更加接近于圆:ΔDV=|ΔD|−|ΔV|=ΔD+ΔV=2(ΔD−x)−1
若ΔDV>0,选取V,若ΔDV<0,选取D
从上述表格中可以看出,一旦我们知道当前点p(x,y),同时计算出ΔD,则我们就能确定从H(x+1,y)、V(x,y−1)、D(x+1,y−1)三点中选取合适的点。
3、计算增量
假设当前点为p(x,y),下一个选取的点为pˊ(xˊ,yˊ)此时 ΔD=F(x+1,y−1)=(x+1)2+(y−1)2+R2,分为三种情况:
1、选取ΔD(x+1,y−1),则xˊ=x+1, yˊ=y−1
ΔDD=F(xˊ+1,yˊ−1)=(x+2)2+(y−2)2−R2=ΔD+2xˊ−2yˊ+2
2、选取H(x+1,y),则xˊ=x+1, yˊ=y
ΔDH=F(xˊ+1,yˊ)=(x+2)2+(y−1)2−R2=ΔD+2xˊ+1
3、选取V(x,y−1),则xˊ=x, yˊ=y−1
ΔDV=F(xˊ,yˊ−1)=(x+1)2+(y−2)2−R2=ΔD−2yˊ+1
以上我们分别计算出了做出三种不同寻则之后各个情况的ΔD值,即我们确定了ΔD的增量关系,这是我们算法成功的关键。
4、得出代码
当得到增量关系后,一切就变得很简单,初始点一定是(0,R),从初始点开始不断递增,直到画满整个第一象限,同时利用对称性,画出整个圆。参考代码如下:
void Circle::DrawPic(CDC *pDC)作者博客: 点击打开链接
{
/*四分圆画图*/
int d = 2-2*r;
int dv,dh;
CPoint cur(0,r);
enum{H,D,V} choice;
for(;cur.y >= 0;)
{
//画出点
pDC->SetPixel(ps.x+cur.x,ps.y+cur.y,RGB(0,0,0));
pDC->SetPixel(ps.x+cur.x,ps.y-cur.y,RGB(0,0,0));
pDC->SetPixel(ps.x-cur.x,ps.y+cur.y,RGB(0,0,0));
pDC->SetPixel(ps.x-cur.x,ps.y-cur.y,RGB(0,0,0));
if(d==0)
{
choice=D;
}
else if(d < 0)
{
dh = 2*(d+cur.y)-1;
choice=dh>0?D:H;
}
else
{
dv = 2*(D-cur.x)-1;
choice=dv>0?D:V;
}
switch(choice)
{
case H:++cur.x;d=d+cur.x*2+1;break;
case D:++cur.x;--cur.y;d=d+(cur.x-cur.y+1)*2;break;
case V:--cur.y;d=d-cur.y*2+1;break;
}
}
}