#!/usr/bin/python from __future__ import division from graphics import * import math # Dimensions of graphics window height = 800 width = 1200 colors = [0] # Radius of shape about the Y axis radius = 1000 # Viewing angle, in degrees to the horizontal va = 10 # Wavelength of sine wave in pixels wavelength = 170 # Height of the figure at the centre (see exponential decay, below) centre_amplitude = 500 # Plot granularity. Affects texture but not overall shape xstep = 1 zstep = 10 # Viewing angle doesn't change, so calculate its sine and cosine now (optimization). var = math.radians(va) sinvar = math.sin(var) cosvar = math.cos(var) win = GraphWin(sys.argv[0], width, height, autoflush=False) win.setCoords(-width/2, -height/2, width/2, height/2) # Image is symmetrical, so iterate x over half the full range (-radius to radius) # and plot both halves at the same time (optimisation). for x in range(-radius, 0, xstep): # Pre-set maximums for hidden surface removal later maxy = -height miny = height # Optimisation: calculate and store this once instead of for every z later xsquared = x*x # The start (and end) of the z range for this x. zlimit = int(math.sqrt(radius*radius - xsquared)) # This range is really just -zlimit to zlimit, step zstep. The reverse # and addition here is just so that the range is symmetrical about zero, # making the pixels line up properly even at high viewing angles. # A simply range(-zlimit, zlimit) produces the same shape but the # texture is not uniform. for z in list(reversed(range(0, -zlimit, -zstep))) + range(0, zlimit, zstep): # Distance of this point from the Y axis, horizontally r = math.sqrt(xsquared + z*z) # Amplitude of wave # Reciprocal decay: more pointy amplitude = 5000*(1/(0.5*r+1)) # Exponential decay: smoother #amplitude = centre_amplitude*(0.990**r) # y is a sinusoid of r, giving the wavy shape. #y = amplitude*math.sin(math.radians(r*(360/wavelength))) y = amplitude*math.sin(math.radians(r*(360/wavelength))) # "Rotate" the 3D image towards the viewer, about the x axis, to give # the viewing angle projection projy = z*sinvar + y*cosvar # Plot the points if (projy > maxy) or (projy < miny): pt = Point(x, projy) pt.draw(win) pt = Point(-x, projy) pt.draw(win) # Hidden surface removal if projy > maxy: maxy = projy if projy < miny: miny = projy # Tp speed up the drawing, remove the indent of the following line # To slow down, increase the indent, putting it into the z loop win.update() # Wait for user to click on image or terminate program print "Done" win.getMouse() win.close()