Search code examples
pythonpygamegeometryantialiasing

Draw not-filled antialiased circles with pygame


I am creating a python module to simplify Pygame which I find rather complicated. It has an antialiasing mode that can be enabled and disabled.

I can draw not-antialiased circles easily using pygame.draw

pygame.draw.circle(window, circlecolor, center, radius, 0 if filled else line_width)

But I have to use pygame.gfxdraw to have antialiasing. I can draw filled antialiased circles by combining gfxdraw.aacircle and filled_circle but I can't draw not filled antialiased circles except if they have a thickness of 1 pixel (gfxdraw.aacircle doesn't have a thickness argument) I already have a function drawing thick antialiased lines which is the same as this

My question is how can I create not-filled antialiased circles? The solution I found was to draw them manually by drawing multiple connected lines to form the circle but I don't know how to do that and there might be a faster solution. Also I can't to draw a big circle and a smaller one for the center because the center wouldn't be transparent.


Solution

  • Basically I drew a polygon with points on the outline of the circle every 3° and I did that for the inside and the outside of the circle then all the points were connected and it made an antialiased thick circle. I also use this for arcs

    def arc(center, xradius, yradius, start_angle, stop_angle, color=BLACK)
        arc_length = (stop_angle - start_angle)  # Arc length
        segment_length = math.radians(3) * min(xradius, yradius)  # Length of one segment
        segment_length = max((segment_length, 2))  # Minimum length of 2
    
        nb_pts = int(arc_length/2*xradius*yradius / segment_length) + 1  # Nb points
        angle = arc_length / (nb_pts-1)  # Angle between each points
        points = []
        width = line_width//2  # Line thickness (half on each side of the circle)
        for i in range(nb_pts):  # Inner border
            x = round(math.cos(start_angle + angle*i) * (xradius-width) + center[0])
            y = round(-math.sin(start_angle + angle*i) * (yradius-width) + center[1])  # - is for counter clockwise
            points.append((x, y))  # Add point
    
        for i in range(nb_pts-1, -1, -1):  # Outer border
            x = round(math.cos(start_angle + angle*i) * (xradius+width) + center[0])
            y = round(-math.sin(start_angle + angle*i) * (yradius+width) + center[1])
            points.append((x, y))  # Add point
    
        polygon(points, color, True)  # True is for filled polygon
    

    And I call the function like this to draw a circle changing xradius and yradius for an ellipse

    arc(center, radius, radius, 0, 2*math.pi, color)