Skip to content

Instantly share code, notes, and snippets.

@fogleman
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fogleman/2a892f9d1fe8e72d6b03 to your computer and use it in GitHub Desktop.
Save fogleman/2a892f9d1fe8e72d6b03 to your computer and use it in GitHub Desktop.
L-system
from math import sin, cos, radians
import cairo
import random
import re
class System(object):
def __init__(self, rules):
self.rules = rules
self.pattern = re.compile('|'.join('(%s)' % x for x in rules))
def step(self, value):
def func(match):
rule = self.rules[match.group(0)]
if isinstance(rule, basestring):
return rule
return random.choice(rule)
return self.pattern.sub(func, value)
def run(self, start, iterations):
result = [start]
for i in range(iterations):
result.append(self.step(result[-1]))
return result
def run(program, dc):
angle = radians(25)
state = (0.0, 0.0, -radians(45))
stack = []
minx = maxx = miny = maxy = 0
for instruction in program:
x, y, a = state
if instruction == 'F':
x += cos(a)
y += sin(a)
if dc:
dc.line_to(x, y)
dc.stroke()
dc.move_to(x, y)
elif instruction == '-':
a -= angle
elif instruction == '+':
a += angle
elif instruction == '[':
stack.append(state)
elif instruction == ']':
x, y, a = stack.pop()
if dc:
dc.move_to(x, y)
state = (x, y, a)
minx = min(minx, x)
miny = min(miny, y)
maxx = max(maxx, x)
maxy = max(maxy, y)
return (minx, miny, maxx, maxy)
def render(program):
size = 1024
pad = 40
minx, miny, maxx, maxy = run(program, None)
width, height = size, size * ((maxy - miny) / (maxx - minx))
width, height = int(width + pad), int(height + pad)
scale = size / (maxx - minx)
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height)
dc = cairo.Context(surface)
dc.set_line_cap(cairo.LINE_CAP_ROUND)
# dc.set_line_width(3)
dc.set_source_rgba(0, 0, 0, 1)
dc.paint()
dc.translate(pad / 2, pad / 2)
dc.scale(scale, scale)
dc.translate(-minx, -miny)
dc.set_source_rgba(1, 1, 1, 0.1)
dc.move_to(0, 0)
run(program, dc)
surface.write_to_png('output.png')
def main():
system = System({
'X': 'F-[[X]+X]+F[+FX]-X',
'F': 'FF',
})
program = system.run('X', 9)[-1]
render(program)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment