这里仅讨论圆心位于坐标原点的圆的扫描转换算法,对于圆心不在原点的圆,可先用平移变换,将它的圆心平移到原点,然后进行扫描转换,最后再平移到原来的位置。
有几种较容易的方法可以得到圆的扫描转换,但是效率都不高。例如:直角坐标法和极坐标法:
1、直角坐标法
圆的直角坐标方程为 x2+y2=R2
若取x作为自变量,解出y,得到
我们可以先扫描转换四分之一的圆周。让自变量x从0到R以单位步长增加,在每一步时可解出y,然后调用画点函数即可逐点画出圆。但这样做,由于有乘方和平方根运算,并且都是浮点运算,算法效率不高。而且当x接近R值时(圆心在原点),在圆周上的点(R,0)附近,由于圆的斜率趋于无穷大,使得圆周上有较大的间隙。
2、极坐标法
假设圆周上一点P(x,y)处的半径与x轴的夹角为θ,则圆的极坐标方程为
利用下面将要介绍的圆周上点的对称性,那么自变量θ的取值范围就是(0,45°)。这个方法涉及三角函数计算和乘法运算,计算量较大。因此,也不是一种有效的方法。
一、 圆的八分对称性
圆心位于原点的圆有四条对称轴x=0、y=0、x=y和x=-y,见下图。从而若已知圆弧上一点P(x,y),就可以得到其关于四条对称轴的七个对称点,这种性质称为八分对称性。因此只要能画出八分之一的圆弧,就可以利用对称性的原理得到整个圆弧。下面的函数CirclePoints()用来显示P(x,y)及其七个对称点。
void CirclePoints(x,y,color) int x,y,color; { putpixel(x,y,color); putpixel(x,-y,color); putpixel(-x,y,color); putpixel(-x,-y,color); putpixel(y,x,color); putpixel(y,-x,color); putpixel(-y,x,color); putpixel(-y,-x,color); } | 圆的八分对称性 |
注意:
当圆心不在原点时,只须在putpixel()函数中加上平移量x0、y0(圆心坐标)即可。
例如:
当 x0=300,y0=200时,则:
…
putpixel(x0+x,y0+y,color);
putpixel(x0+x,y0-y,color);
putpixel(x0-x,y0+y,color);
putpixel(x0-x,y0-y,color);
putpixel(x0+y,y0+x,color);
putpixel(x0+y,y0-x,color);
putpixel(x0-y,y0+x,color);
putpixel(x0-y,y0-x,color);
…
二、中点算法生成圆
中点画圆算法在一个方向上取单位间隔,在另一个方向的取值由两种可能取值的中点离圆的远近而定。实际处理中,用决策变量的符号来确定象素点的选择,因此算法效率较高。
(一)、中点画圆算法描述
设要显示圆的圆心在原点(0,0),半径为R,起点在(0,R)处,终点在(
,
)处,顺时针生成八分之一圆,利用对称性扫描转换全部圆。
为了应用中点画圆法,我们定义一个圆函数
任何点(x,y)的相对位置可由圆函数的符号来检测:
如下图所示,图中有两条圆弧A和B,假定当前取点为Pi(xi,yi),如果顺时针生成圆,那么下一点只能取正右方的点E(xi+1,yi)或右下方的点SE(xi+1,yi-1)两者之一。
![](http://course.cug.edu.cn/cugFirst/computer_graphics/class/course/images/2-2-2-a-3.gif)
中点画线算法
假设M是E和SE的中点,即
,则:
1、当
F(M)
<0时,
M在圆内(圆弧
A),这说明点E距离圆更近,应取点
E作为下一象素点;
2、当
F(M)
>0时,
M在圆外(圆弧
B),表明
SE点离圆更近,应取
SE点;
3、当
F(M)
=0时,在
E点与
SE点之中随便取一个即可,我们约定取
SE点。
(二)、中点画圆算法思想
因此,我们用中点M的圆函数作为决策变量di,同时用增量法来迭代计算下一个中点M的决策变量di+1。
下面分两种情况来讨论在迭代计算中决策变量di+1的推导。
1、见图(a),若di<0,则选择E点,接着下一个中点就是
,这时新的决策变量为:
![](http://course.cug.edu.cn/cugFirst/computer_graphics/class/course/images/2-2-2-a-3a.gif)
(a)(di<0) 中点画线算法
式(2-22)减去(2-21)得:
2、见图(b),若di≥0,则选择SE点,接着下一个中点就是
,这时新的决策变量为:
![](http://course.cug.edu.cn/cugFirst/computer_graphics/class/course/images/2-2-2-a-3b.gif)
(b)(di≥0) 中点画线算法
式(2-24)减去(2-21)得:
我们利用递推迭代计算这八分之一圆弧上的每个点,每次迭代需要两步处理:
(1)用前一次迭代算出的决策变量的符号来决定本次选择的点。
(2)对本次选择的点,重新递推计算得出新的决策变量的值。
剩下的问题是计算初始决策变量d0,如下图所示。对于初始点(0,R),顺时针生成八分之一圆,下一个中点M的坐标是
,所以:
![](http://course.cug.edu.cn/cugFirst/computer_graphics/class/course/images/2-2-2-a-11.gif)
生成圆的初始条件和圆的生成方向
(三)、中点画圆算法实现
1、输入:圆半径r、圆心(x0,y0);
2、确定初值:x=0,y=r、d=5/4-r;
3、While(x<=y)
{
·利用八分对称性,用规定的颜色color画八个象素点(x,y);
· 若d≥0
{
y=y-1;
d=d+2(x-y)+5);
}
否则
d=d+2x+3;
·x=x+1;
}
(四)、中点画圆算法完善
在上述算法中,使用了浮点数来表示决策变量d。为了简化算法,摆脱浮点数,在算法中全部使用整数,我们使用e=d-1/4代替d。显然,初值d=5/4-r对应于e=1-r。决策变量d<0对应于e<-1/4。算法中其它与d有关的式子可把d直接换成e。又由于e的初值为整数,且在运算过程中的迭代值也是整数,故e始终是整数,所以e<-1/4等价于e<0。因此,可以写出完全用整数实现的中点画圆算法。
要求:写出用整数实现的中点画圆算法程序,并上机调试,观看运行结果。
(五)、中点画圆算法程序
void MidpointCircle(int x0,int y0,int r,int color)
{
int x,y;
float d;
x=0;
y=r;
d=5.0/4-r;
while(x<=y)
{
putdot(x0,y0,x,y,color);
if(d<0)
d+=x*2.0+3;
else
{
d+=2.0*(x-y)+5;
y--;
}
x++;
}
}
putdot(x0,y0,x,y,color)
{
putpixel(x0+x,y0+y,color);
putpixel(x0+x,y0-y,color);
putpixel(x0-x,y0+y,color);
putpixel(x0-x,y0-y,color);
putpixel(x0+y,y0+x,color);
putpixel(x0+y,y0-x,color);
putpixel(x0-y,y0+x,color);
putpixel(x0-y,y0-x,color);
}