Anti-aliased Arc Pygame

我的梦境 提交于 2020-01-14 09:21:06

问题


I am trying to code a simple circle timer in Python using Pygame. At the moment it looks like this:

As you can see, the blue line is very wavy and has white dots in it. I am achieving this blue line by using pygame.draw.arc() function, but it is not anti-aliased and looks bad. I would like it to be anti-aliased, but gfxdraw module which should let me achieve this, doesn't support arc width selection. Here's code snippet:

pygame.draw.arc(screen, blue, [center[0] - 120, center[1] - 120, 240, 240], pi/2, pi/2+pi*i*koef, 15)
pygame.gfxdraw.aacircle(screen, center[0], center[1], 105, black)
pygame.gfxdraw.aacircle(screen, center[0], center[1], 120, black)

回答1:


I am not aware of any pygame function that would solve this problem, meaning you basically have to program a solution yourself (or use something other than pygame), since draw is broken as you've noted and gfxdraw won't give you the thickness.

One very ugly but simple solution is to draw multiple times over the arc segments, always slightly shifted to "fill in" the missing gaps. This will still leave some aliasing at the very front of the timer arc, but the rest will be filled in.

import pygame
from pygame.locals import *
import pygame.gfxdraw
import math

# Screen size
SCREEN_HEIGHT = 350
SCREEN_WIDTH = 500

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREY = (150, 150, 150)
RED = (255,0,0)


 # initialisation
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
done = False
clock = pygame.time.Clock()

# We need this if we want to be able to specify our
#  arc in degrees instead of radians
def degreesToRadians(deg):
    return deg/180.0 * math.pi

# Draw an arc that is a portion of a circle.
# We pass in screen and color,
# followed by a tuple (x,y) that is the center of the circle, and the radius.
# Next comes the start and ending angle on the "unit circle" (0 to 360)
#  of the circle we want to draw, and finally the thickness in pixels
def drawCircleArc(screen,color,center,radius,startDeg,endDeg,thickness):
    (x,y) = center
    rect = (x-radius,y-radius,radius*2,radius*2)
    startRad = degreesToRadians(startDeg)
    endRad = degreesToRadians(endDeg)

    pygame.draw.arc(screen,color,rect,startRad,endRad,thickness)


# fill screen with background
screen.fill(WHITE)
center = [150, 200]
pygame.gfxdraw.aacircle(screen, center[0], center[1], 105, BLACK)
pygame.gfxdraw.aacircle(screen, center[0], center[1], 120, BLACK)

pygame.display.update()

step = 10
maxdeg = 0

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    maxdeg = maxdeg + step
    for i in range(min(0,maxdeg-30),maxdeg):
        drawCircleArc(screen,RED,(150,200),119,i+90,max(i+10,maxdeg)+90,14)  
        #+90 will shift it from starting at the right to starting (roughly) at the top
    pygame.display.flip()

    clock.tick(2)  # ensures a maximum of 60 frames per second

pygame.quit()

Note that I have copied degreesToRadians and drawCircleArc from https://www.cs.ucsb.edu/~pconrad/cs5nm/08F/ex/ex09/drawCircleArcExample.py

I do not generally recommend this solution, but it might do in a pinch.




回答2:


Ok, this is really old, but why not try to draw pies instead. For example draw a pie, then an unfilled circle as the outside ring and then a filled circle as the inside and another unfilled circle as the inside ring.

So pie -> unfilled circle -> filled circle -> unfilled.

The order is somewhat arbitrary but if u still have this problem give it a try. (Btw I haven't tried it but I think it will work)




回答3:


I did it creating the arc with a polygon.

def drawArc(surface, x, y, r, th, start, stop, color):
    points_outer = []
    points_inner = []
    n = round(r*abs(stop-start)/20)
    if n<2:
        n = 2
    for i in range(n):
        delta = i/(n-1)
        phi0 = start + (stop-start)*delta
        x0 = round(x+r*math.cos(phi0))
        y0 = round(y+r*math.sin(phi0))
        points_outer.append([x0,y0])
        phi1 = stop + (start-stop)*delta
        x1 = round(x+(r-th)*math.cos(phi1))
        y1 = round(y+(r-th)*math.sin(phi1))
        points_inner.append([x1,y1])
    points = points_outer + points_inner        
    pygame.gfxdraw.aapolygon(surface, points, color)
    pygame.gfxdraw.filled_polygon(surface, points, color)

The for loop could certainly be created more elegantly with a generator, but I am not very sophisticated with python.

The arc definitely looks nicer than pygame.draw.arc, but when I compare it to the screen rendering on my mac, there is room for improvement.



来源:https://stackoverflow.com/questions/38143135/anti-aliased-arc-pygame

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!