一个圆可以切成8块,这每一块都对称;
沿x轴对称,y值符号变,x不变;
沿y轴对称,x值不变,y符号变相反;
沿y=x对称,y和x交换。
一个概念:这样我们只需要画第一象限的1/8圆弧即可;沿x轴方向进行描点画圆,x每次增加1,y减1否,需要做判断,这也是我们算法的核心:
y到底要不要减小,我们取(x+1,y-0.5)的点到圆心的距离与r作比较,如果该点在园外,则减,否则不变。即 插值公式:F(x+1, y-0.5) = (x+1)2+(y-0.5)2 - r2然后递推得到递推公式:
1. 当d=F(x+1,y-0.5)-r2 > 0: 则下一个d值:d = F(x + 2, y - 1.5) = (x + 2)^2 + (y - 1.5)^2 - R^2 = (x + 1)^2 + (x - 0.5)^2 - R^2 + 2x + 3 - 2y + 2 = d + 2x - 2y + 5;
2. 当前d = F(x + 1, y - 0.5) < 0,则y不变,只有x增1,则下一d值为d = F(x + 2, y - 0.5) = d + 2x + 3;
3. d的初值,d0 = F(1, R - 0.5) = 1.25 - R,因为递推关系中只有整数运算,所以d取初值1 - R。
python代码:
from matplotlib import pyplot as plt
import numpy as np
def draw_circle(centre, r, out):
a = 0
b = r
d = 1-r
x0 = centre[0]
y0 = centre[1]
while a <= b:
out[0].append(x0+a)
out[1].append(y0+b)
out[0].append(x0+b)
out[1].append(y0+a) #1/8circle duicheng
out[0].append(x0-a) #y duicheng
out[1].append(y0+b)
out[0].append(x0-b)
out[1].append(y0+a)
out[0].append(x0+a) #xduicheng
out[1].append(y0-b)
out[0].append(x0+b)
out[1].append(y0-a)
out[0].append(x0-a) #yuandian duicheng
out[1].append(y0-b)
out[0].append(x0-b)
out[1].append(y0-a)
a = a + 1
if (d < 0):
d = d + 2*a + 3
else:
d = d + 5 + 2*(a-b)
b = b - 1
pix_array=[[]for i in range(2)]
draw_circle((0,0), 1000, pix_array)
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.scatter(pix_array[0], pix_array[1], marker='.')
plt.show()
结合我做嵌入式正点原子的代码:
他这里给系数都乘2了,效果和上面一样,bresenham算法对半径越大的,越圆。
//画圆
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r)
{
int a,b;
int di;
a=0;b=r;
di=3-(r<<1); //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint(x0+a,y0-b); //5
LCD_DrawPoint(x0+b,y0-a); //0
LCD_DrawPoint(x0+b,y0+a); //4
LCD_DrawPoint(x0+a,y0+b); //6
LCD_DrawPoint(x0-a,y0+b); //1
LCD_DrawPoint(x0-b,y0+a);
LCD_DrawPoint(x0-a,y0-b); //2
LCD_DrawPoint(x0-b,y0-a); //7
a++;
//使用Bresenham算法画圆
if(di<0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
}
}
https://blog.csdn.net/bagboy_taobao_com/article/details/5774628
正点原子stm32 lcd驱动教程