# Circles on Circles # adapted from Pascal Program by Bernie Gunn # by Kirby Urner # Version 1.0: Sept 19, 2004 # Requires PIL (Python Imaging Library) from math import sin, cos, radians import Image, ImageDraw, ImageFont # PIL must be installed def setup(rot, width, height, bg = 'White', txtcolor = "Blue"): """ Initialize/return canvas, draw objects, draw text """ canvas = Image.new('RGB',(width, height), bg) draw = ImageDraw.Draw(canvas) # add title and caption to canvas font1 = ImageFont.truetype('verdana.ttf', 32) # requires latest PIL, ttfs font2 = ImageFont.truetype('verdana.ttf', 16) title = "Circles on Circles" wtitle, htitle = font1.getsize(title) # used to place text caption = "Rotation Factor = %s" % rot wcaption = font2.getsize(caption)[0] draw.text((width/2 - wtitle/2, 20), title, font = font1, fill = txtcolor) draw.text((height/2 - wcaption/2, 40 + htitle), caption, font = font2, fill = txtcolor) return (canvas, draw) # objects required in other modules, avoiding any global variables def mainloop(rot, width, height, draw, color = 'Black'): """ Compute the points, draw lines connecting them """ R1 = 140 R2 = 140 j = 0 xcenter = width/2 ycenter = height/2 while j <= 360: k = j * rot y1 = round(sin(radians(j)) * R1) x1 = round(cos(radians(j)) * R2) y2 = round(sin(radians(k)) * R1) x2 = round(cos(radians(k)) * R2) point = (x1 + x2 + xcenter, y1 + y2 + ycenter) if j > 0: draw.line([oldpoint, point], color) oldpoint = point j += 0.25 # quarter-degree increments (smoother curves) def finish(canvas): """ Display the canvas in a default viewer, then save it to file """ canvas.show() # in Windows, uses default bmp viewer canvas.save("./Lib/site-packages/mycircles.png","PNG") # presuming this path exists print "Image saved." def main(width=800, height=800): rot = int(raw_input("Rotate Outer circle by what factor of inner?: ")) canvas, draw = setup(rot, width, height, bg='Black', txtcolor='Yellow') # bg, txtcolor optional mainloop(rot, width, height, draw, color='Orange') # draw color optional finish(canvas) # added so this may run as a script, vs imported as a module if __name__ == "__main__": main()