Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Artifacts when drawing primitives with pygame?

Tags:

python

pygame

I'm working on some code involving use of the pygame library to draw a circle to a surface. The code to draw the circle looks something like the following:

  surf = pygame.Surface((2000,2000))
  pygame.draw.circle(surf, 
                     pygame.Color("white"),
                     (1000,1000),
                     508,
                     50)

The problem is that the resulting circle has artifacts Circle with artifacts

Is there anyway to draw a circle like this without getting these artifacts?

like image 479
Paul Wicks Avatar asked Apr 13 '12 21:04

Paul Wicks


2 Answers

What you see is most likely a problem with pygame.draw.circle implementation. Most likely pygame developer foolishly assumed that you can draw thick circle by drawing several circles in sequence, increasing radius by one for every circle. That's not going to work in practice and you'll get moire pattern like the one you see. Try increasing circle line thickness by 100 or 200 and see what happens. If it gets worse, then it is pygame.draw.circle's fault.

A solution would be to provide your own circle rendering routine. This can be certainly be done, but for optimum performance it makes sense to do it in C/C++ extension module for pygame OR using OpenGL (with or without fragment shaders).

To get a perfect circle for every scanline you'll have to calculate start and end of filled area for every scanline. It might be possible to do this in python with tolerable performance by using pygame.draw.line to draw individual scanlines.

like image 155
SigTerm Avatar answered Oct 07 '22 16:10

SigTerm


This bug is mentioned in the comments for the circle and arc methods. There's one workaround in the comments of the draw.circle documentation. This is adapted from that workaround:

def draw_outlined_circle(surf, color, origin, radius, thickness):
    width = radius * 2 + thickness * 2
    background = (0, 0, 0, 0)
    circle = pygame.Surface((width, width)).convert_alpha()
    rect = circle.get_rect()
    circle.fill(background)
    pygame.draw.circle(circle, color, rect.center, radius)
    pygame.draw.circle(circle, background, rect.center, radius - thickness)
    surf.blit(circle, (origin[0] - (rect.w / 2), origin[1] - (rect.w / 2)))

This method uses an extra Surface and draws two circles: a smaller circle inside of a larger one to achieve the same effect. The smaller circle's fill color has an alpha of 0, so the full circle's center appears transparent.

EDIT: From the above comment, I see the behavior is mentioned in the pygame FAQ as well.

like image 20
0eggxactly Avatar answered Oct 07 '22 15:10

0eggxactly