我需要使用具有这些约束的像素绘制圆圈:
中点算法无法使用,但我发现Eric Andres写了我想要的确切内容。该算法可以在this article中以“半整数居中圆”的名称找到。对于那些无法访问它的人,我把有趣的部分放在问题的最后。
我在实现算法时遇到了困难。我使用Python语法在Processing中复制了算法(为了便于可视化):
def half_integer_centered_circle(xc, yc, R):
x = 1
y = R
d = R
while y >= x:
point(xc + x, yc + y)
point(xc + x, yc - y + 1)
point(xc - x + 1, yc + y)
point(xc - x + 1, yc - y + 1)
point(xc + y, yc + x)
point(xc + y, yc - x + 1)
point(xc - y + 1, yc + x)
point(xc - y + 1, yc - x + 1)
if d > x:
d = d - x
x = x + 1
elif d < R + 1 - y:
d = d + y - 1
y = y - 1
else:
d = d + y - x - 1
x = x + 1
y = y - 1
point()
函数只绘制给定坐标处的像素。另请注意,在文章中,x
初始化为S
,这很奇怪,因为其他地方没有S
(根本没有解释),但据说这个圈子从(x,y)=(1,R)开始,所以我写了x = 1
。
我得到的结果是1像素到20像素之间的半径:
如您所见,圆圈之间有孔,R = 3的圆与给定的例子不同(见下文)。此外,与中点算法相比,圆圈并不是真正的圆形。
如何获得正确的结果?
Eric Andres原创算法:
答案 0 :(得分:1)
我不明白该算法在该论文中的呈现方式。当我读到它时,与案例(b)相关的else if
子句没有前面的if
。当我以书面形式转录时,我得到与你相同的结果
查看文本,而不是伪代码,文章似乎建议采用以下形式的算法:
x = 1
y = R
while x is less than or equal to y:
draw(x, y)
# ...
if the pixel to the right has radius between R - 1/2 and R + 1/2:
move one pixel to the right
if the pixel below has radius between R - 1/2 and R + 1/2:
move one pixel down
else:
move one pixel diagonally down and right
这似乎有道理。在python:
#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as pp
fg = pp.figure()
ax = fg.add_subplot(111)
def point(x, y, c):
xx = [x - 1/2, x + 1/2, x + 1/2, x - 1/2, x - 1/2 ]
yy = [y - 1/2, y - 1/2, y + 1/2, y + 1/2, y - 1/2 ]
ax.plot(xx, yy, 'k-')
ax.fill_between(xx, yy, color=c, linewidth=0)
def half_integer_centered_circle(R, c):
x = 1
y = R
while y >= x:
point(x, y, c)
point(x, - y + 1, c)
point(- x + 1, y, c)
point(- x + 1, - y + 1, c)
point(y, x, c)
point(y, - x + 1, c)
point(- y + 1, x, c)
point(- y + 1, - x + 1, c)
def test(x, y):
rSqr = x**2 + y**2
return (R - 1/2)**2 < rSqr and rSqr < (R + 1/2)**2
if test(x + 1, y):
x += 1
elif test(x, y - 1):
y -= 1
else:
x += 1
y -= 1
for i in range(1, 5):
half_integer_centered_circle(2*i - 1, 'r')
half_integer_centered_circle(2*i, 'b')
pp.axis('equal')
pp.show()
这似乎按预期工作。请注意,为简单起见,我删除了圆心。它应该很容易再次添加。
编辑已实现我可以匹配半径3图像,如果我稍微调整一下逻辑。
答案 1 :(得分:1)
我一直在调查此事,并在原始论文中发现了三个问题:
此处复制的算术圆(论文中的图10.a)与“半整数居中圆”的形式定义不一致。在一种情况下,到中心的距离必须在R-1/2和R + 1/2之间,在另一种情况下在整数值之间。结果是,如果正确实施,这个特定的算法永远不会产生图10.a的圆圈。
算法伪代码的一个不等式有一个错误:案例(b)的测试应该是d <= (R + 1 - y)
而不是d < (R + 1 - y)
。
满足x == y的所有像素仅具有4倍对称性(不是8倍),并且由算法生成两次。虽然生成重复的像素对于绘图例程可能不是问题,但是我感兴趣的应用程序是不可接受的。但是,通过添加对x == y条件的简单检查并跳过四个重复的可以很容易地解决这个问题。像素。
原始问题的python代码包括上面提到的不等式错误以及由于其中一个应该读取d = d + (y - x - 1)
的表达式中缺少括号而导致的其他错误。
以下实现修复了所有这些并与python2和python3兼容(point()函数中没有整数除法问题):
import numpy as np
import matplotlib.pyplot as pp
fg = pp.figure()
ax = fg.add_subplot(111)
def point(x, y, c):
xx = [x - 0.5, x + 0.5, x + 0.5, x - 0.5, x - 0.5 ]
yy = [y - 0.5, y - 0.5, y + 0.5, y + 0.5, y - 0.5 ]
ax.plot(xx, yy, 'k-')
ax.fill_between(xx, yy, color=c, linewidth=0)
def half_integer_centered_circle(R, c):
x = 1
y = R
d = R
while y >= x:
point(x, y, c)
point(x, - y + 1, c)
point(- x + 1, y, c)
point(- x + 1, - y + 1, c)
if y != x:
point(y, x, c)
point(y, - x + 1, c)
point(- y + 1, x, c)
point(- y + 1, - x + 1, c)
if d > x:
d = d - x
x = x + 1
elif d <= R + 1 - y:
d = d + y - 1
y = y - 1
else:
d = d + (y - x - 1)
x = x + 1
y = y - 1
for i in range(1, 5):
half_integer_centered_circle(2*i - 1, 'r')
half_integer_centered_circle(2*i, 'b')
pp.axis('equal')
pp.show()