绘制直径均匀

时间:2016-03-04 17:08:36

标签: algorithm drawing draw pixel pixels

我需要使用具有这些约束的像素绘制圆圈:

  1. 直径上的像素总数是偶数,
  2. 在半径为R和R + 1的两个圆之间没有空像素(R是整数)。
  3. 中点算法无法使用,但我发现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像素之间的半径:

    Algorithm result

    如您所见,圆圈之间有孔,R = 3的圆与给定的例子不同(见下文)。此外,与中点算法相比,圆圈并不是真正的圆形。

    如何获得正确的结果?

    Eric Andres原创算法:

    Half integer centered circle algorithm

2 个答案:

答案 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()

这似乎按预期工作。请注意,为简单起见,我删除了圆心。它应该很容易再次添加。 enter image description here

编辑已实现我可以匹配半径3图像,如果我稍微调整一下逻辑。

答案 1 :(得分:1)

我一直在调查此事,并在原始论文中发现了三个问题:

  1. 此处复制的算术圆(论文中的图10.a)与“半整数居中圆”的形式定义不一致。在一种情况下,到中心的距离必须在R-1/2和R + 1/2之间,在另一种情况下在整数值之间。结果是,如果正确实施,这个特定的算法永远不会产生图10.a的圆圈。

  2. 算法伪代码的一个不等式有一个错误:案例(b)的测试应该是d <= (R + 1 - y)而不是d < (R + 1 - y)

  3. 满足x == y的所有像素仅具有4倍对称性(不是8倍),并且由算法生成两次。虽然生成重复的像素对于绘图例程可能不是问题,但是我感兴趣的应用程序是不可接受的。但是,通过添加对x == y条件的简单检查并跳过四个重复的可以很容易地解决这个问题。像素。

  4. 原始问题的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()