Recently, while searching for an picture of evolution (specifically, the famous image of the progression from ape to man), I came across an interesting and beautiful evolution simulation. The website is actually about a piece of software called Nodebox that uses Python to draw and manipulate images. The site has loads of amazing examples of its power. Sadly, I don’t have a Mac, so I can’t use the software myself. However, since I’ve been learning create SVG files with Python, I thought I create my own simple version.
Trying to create life-like images using simple recursion effects, which computer algorithms are very good at is something I tried a long time ago, when I first came across The Blind Watchmaker program (there is an example of the applet here – maybe I should try to make my own) in Richard Dawkins’s book of the same name. It was around this time that I also came across L-systems, which can be used to create plant-like fractals, which I’d also like to explore further.
Via the Nodebox site, I discovered the wonderfully named Superformula. This formula allows one to create a myriad of biological-looking shapes by varying just six parameters, which, not incidentally, makes the shapes easy to evolve (though what measure of fitness you would use, I don’t know). All this means that I can experiment with creating biological shapes just by altering the parameters of the Superformula, the colours, the depth of recursion and the change in angle and size every recursion.
Via the Nodebox site, I also discovered the site of a Ludivine Lechat, who has produced some beautiful simulations of life algorithmically. These include plants, cells that evolve and arthropods. Her site is encouraging in that it shows just what is possible, but discouraging in that I doubt I will ever be able to create anything as graceful as her creations.
However, I experimented a bit with some very simple recursion and some created some Python code to draw appropriated scaled and angled Superformula shapes. To create the image above, I also learnt how to create gradients in SVG files, which create quite a nice effect. I think a more lifelike image could be made by layering more levels of recursion or adding more shapes per level. I also need some way to create a proper head (I cheated with the antenna by specifying them separately).
This is the function I wrote for creating a Superformula path:
def Supershape(a, b, m, n1, n2, n3): path =  points = 800 for n in range(points): u = m * math.pi * n / points r = (math.fabs(math.cos(u) / a) ** n2 + math.fabs(math.sin(u) / b) ** n3) ** (-1 / n1) path.append(r) max_r = max(path) normalised_path = [r/max_r for r in path] return normalised_path
The function takes the size values for the Superformula shape and returns the radius of the shape at 800 equally spaced points, normalised so the maximum radius is 1. To display the shape in Pygame I created this function:
def drawShape(radii, colour=(0,0,0), size=20, angle=0): surface = pygame.Surface((size+2, size+2)) surface.fill((255,255,255)) surface.set_colorkey((255,255,255)) size -=2 # Creates a border so whole image is drawn x =  y =  for n in range(len(radii)): u = 2 * math.pi * n / len(radii) x.append(radii[n] * math.cos(u-angle)) y.append(radii[n] * math.sin(u-angle)) if max(x) - min(x) > max(y) - min(y): scale = size/(max(x) - min(x)) else: scale = size/(max(y) - min(y)) midX = 1+size/2 - scale*(min(x) + max(x))/2 midY = 1+size/2 - scale*(min(y) + max(y))/2 points = [(x1*scale + midX, y1*scale + midY) for (x1, y1) in zip (x, y)] pygame.draw.aalines(surface, colour, True, points) return surface
This takes the radii returned by the Supershape function, and draws the shape on a Pygame surface, which is then returned. The function takes optional arguments that define the colour, size and angle of the shape. I have a similar function for drawing a filled shape.
Coincidently, while writing this post, I followed a link on Twitter about cutting bagels into two linked halves, and found that the bagel-cutter had worked on his own method of generating lifelike forms mathematically.