Hi all,
Now that pygame includes the (experimental) gfxdraw module for drawing
shapes, I thought it might interest some to hear about an efficient
circle drawing algorithm I came across:
http://slabode.exofire.net/circle_draw.shtml
(mirror: http://www.mmsguru.com/mirror/circle_cached.html)
The link discusses it in the context of OpenGL, but where the
algorithm is simply about finding out where to put the circle's
vertices, it generalizes rather widely. Below I include a timing
example of using it in pygame with gfxdraw. I know gfxdraw has a
built-in circle drawing function; indeed, as you'll see at the end of
the code, the built-in function is rather faster than either manual
function I create (possibly because it wraps compiled code for
determining the vertices?). However, I thought this example might
still be of use to some, for example those that want to make their own
version of the pie function that draws a filled pie, etc. It's even
possible that whatever compiled code achieves the built-in circle
functions may achieve speed-ups by implementing the more efficient
vertex locating algorithm.
A final note of interest, when polygon() is replaced by aapolygon() in
the manual functions below, the traditional trig approach slows down
quite a bit whereas SiegeLord's approach doesn't seem to slow down
much at all. Not sure why this would be though.
#####START CODE#####
#import requisite libraries
import pygame , math , time
from pygame.locals import *
from pygame.gfxdraw import *
pygame.init()
screen_size = (500,500)
screen = pygame.display.set_mode(screen_size)
screen_rect = screen.get_rect()
screen_x_center = screen_size[0]/2
screen_y_center = screen_size[1]/2
BLACK = (0,0,0)
WHITE = (255,255,255)
screen.fill(BLACK)
radius = 200
#define the standard (slow) circle function
def draw_circle(cx,cy,radius):
points = []
for angle in range(361):
points.append(( \
cx + math.sin(angle) * radius \
, cy + math.cos(angle) * radius \
))
polygon(screen,points,WHITE)
#time the standard circle function
start=time.time()
for i in range(1000):
draw_circle( \
screen_x_center \
, screen_y_center \
, radius \
)
print time.time()-start
#define SiegeLord's (faster) circle function
def draw_circle_fast(cx, cy, radius):
theta = 2 * math.pi / 361
tangetial_factor = math.tan(theta)
radial_factor = math.cos(theta)
x = radius
y = 0
points = []
for ii in range(361):
points.append((x + cx, y + cy))
tx = -y
ty = x
x = x + tx * tangetial_factor
y = y + ty * tangetial_factor
x = x * radial_factor
y = y * radial_factor
polygon(screen,points,WHITE)
#time SiegeLord's function
start=time.time()
for i in range(1000):
draw_circle_fast( \
screen_x_center \
, screen_y_center \
, radius \
)
print time.time()-start
#time the built-in function
start=time.time()
for i in range(1000):
circle( \
screen \
, screen_x_center \
, screen_y_center \
, radius \
, WHITE \
)
print time.time()-start
#####END CODE#####