2. 圆
对于一个圆,这里给出的圆的中点坐标和圆的半径,同样有三种常用方法。最终使用的依旧是Bresenham法。
(1)直角坐标法
根据圆的方程(x– x0) ^ 2 + (y – y0) ^ 2 = r ^2,当一个坐标确定时,另外一个坐标也可以计算出来。为了画出一个完整的圆,因为圆本身具有完美的对称特性,我们画八个r/ sqrt(2)宽度的弧,组成一个圆。之所以选取r/ sqrt(2)是因为这点切线斜率为1,这样画出的圆不会间断。
基本代码:
void draw_circle_Coordinate_3i(int32 x, int32 y, int32 r)
{
int32 i, t, rr = (int32)ceil(r / sqrt(2.0));
for(i=0;i<=rr;++i)
{
t = (int32)sqrt(r * r - i * i);
draw_point_2i(x + i, y + t);
draw_point_2i(x + i, y - t);
draw_point_2i(x + t, y + i);
draw_point_2i(x - t, y + i);
draw_point_2i(x - i, y + t);
draw_point_2i(x - i, y - t);
draw_point_2i(x + t, y - i);
draw_point_2i(x - t, y - i);
}
}
(2)中点画圆法
中点画圆法的基本思想不变,只不过增量的变化要根据圆的公式更改。定义F(x,y) = x ^ 2 + y ^ 2 – r ^ 2,F(x,y) > 0说明点在圆外,F(x,y) < 0说明点在圆内。定义增量D(x,y) = F(x, y) – F(x0, y0),我们考虑圆上方顶点向右绘制的过程,则
D(x+1,y-0.5) = (x+1)^2 + (y–0.5)^2 – x^2 – y^2 = 2x - y + 1.25
D(x+1,y) = (x+1)^2 – x^2 = 2x + 1
D(x+1,y-1) = (x+1)^2 + (y–1)^2 – x^2 – y^2 = 2x – 2y + 2
为了避免浮点数运算,所有D乘以4,则
D(x+1,y-0.5) = 8x - 4y + 5
D(x+1,y) = 8x + 4
D(x+1,y-1) = 8x – 8y + 8
同样利用圆的对称性即可画出完整的圆。
基本代码:
void draw_circle_MidPoint_3i(int32 x, int32 y, int32 r)
{
int32 d, i, j;
int32 rr = (int32)ceil(r / sqrt(2.0));
j = r;
d = - (j<<2) + 5;
for(i=0;i<=rr;++i)
{
draw_point_2i(x + i, y + j);
draw_point_2i(x + i, y - j);
draw_point_2i(x + j, y + i);
draw_point_2i(x - j, y + i);
draw_point_2i(x - i, y + j);
draw_point_2i(x - i, y - j);
draw_point_2i(x + j, y - i);
draw_point_2i(x - j, y - i);
if(d > 0)
{
d -= (i << 3) + 4;
}
else
{
-- j;
d -= (i - j + 1) << 3;
}
}
}
(3)Bresenham法
Bresenham法本质依然与直线相同,交点与整点的距离e(x,y) = 2(x+1)^2 + y^2 + (y-1)^2 – 2r^2,带入初值的e(0,r) = 3 – 2r,选择上方点,e(x+1,y) – e(x, y) = 2(x+2)^2 – 2(x+1)^2 = 4x + 6,选择下方点,e(x+1,y+1) – e(x, y) = 4x + 6 + y^2 + (y-1)^2 – (y+1)^2 – y^2 = 4x –4y + 10。
注:给出代码的计算量和中点画圆法相同。
基本代码:
void draw_circle_Bresenham_3i(int32 x, int32 y, int32 r)
{
int32 e;
int32 i, j;
int32 rr = (int32)ceil(r / sqrt(2.0));
j = r;
e = 3 - (r << 1);
for(i=0;i<=rr;++i)
{
draw_point_2i(x + i, y + j);
draw_point_2i(x + i, y - j);
draw_point_2i(x + j, y + i);
draw_point_2i(x - j, y + i);
draw_point_2i(x - i, y + j);
draw_point_2i(x - i, y - j);
draw_point_2i(x + j, y - i);
draw_point_2i(x - j, y - i);
if(e < 0)
{
e += (i << 2) + 6;
}
else
{
e += ((i - j)<<2) + 10;
-- j;
}
}
}