我正在尝试实现Xiaolin Wu在他的Siggraph'91论文“一种高效的抗锯齿技术”中描述的“快速抗锯齿圆形生成器”例程。
这是我使用Python 3和PySDL2编写的代码:
def draw_antialiased_circle(renderer, position, radius):
def _draw_point(renderer, offset, x, y):
sdl2.SDL_RenderDrawPoint(renderer, offset.x - x, offset.y + y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x + x, offset.y + y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x - x, offset.y - y)
sdl2.SDL_RenderDrawPoint(renderer, offset.x + x, offset.y - y)
i = 0
j = radius
d = 0
T = 0
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, sdl2.SDL_ALPHA_OPAQUE)
_draw_point(renderer, position, i, j)
while i < j + 1:
i += 1
s = math.sqrt(max(radius * radius - i * i, 0.0))
d = math.floor(sdl2.SDL_ALPHA_OPAQUE * (math.ceil(s) - s) + 0.5)
if d < T:
j -= 1
T = d
if d > 0:
alpha = d
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha)
_draw_point(renderer, position, i, j)
if i != j:
_draw_point(renderer, position, j, i)
if (sdl2.SDL_ALPHA_OPAQUE - d) > 0:
alpha = sdl2.SDL_ALPHA_OPAQUE - d
sdl2.SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha)
_draw_point(renderer, position, i, j + 1)
if i != j + 1:
_draw_point(renderer, position, j + 1, i)
这是我认为在他的论文中所描述的天真实现,但有一个例外,即我将半径值分配给了
j
而不是i
,因为我可能误解了什么或者他的论文中有错误。事实上,他用半径值初始化i
,用0
初始化j
,然后定义循环条件i <= j
,只有当半径为0
时才能为真。这个改变使我对所描述的内容进行了一些其他次要的修改,我还将if d > T
更改为if d < T
,只是因为它看起来有问题。
这个实现大部分情况下都可以正常工作,除了每个八分之一圆的开头和结尾会出现一些小问题。
上面的圆的半径为1。你可以看到在每个八分之一圆的开始处(例如在(0, 1)区域),在循环内绘制的像素没有与在循环开始前绘制的第一个像素对齐。此外,在每个八分之一圆的末尾(例如在(sqrt(2) / 2, sqrt(2) / 2)
区域),出现了一些严重的问题。我成功地通过将if d < T
条件更改为if d <= T
来消除这个最后的问题,但是同样的问题出现在每个八分之一圆的开始处。
问题1:我做错了什么?
问题2:如果我想要输入位置和半径为浮点数,会有什么陷阱吗?