lindenmayer systems

This commit is contained in:
Michael Fogleman 2017-04-26 21:10:46 -04:00
parent ad318ccf54
commit 44eae1157f
3 changed files with 75 additions and 0 deletions

View File

@ -1,5 +1,6 @@
from .device import Device from .device import Device
from .drawing import Drawing from .drawing import Drawing
from .lindenmayer import LSystem
from .paths import simplify_paths, sort_paths, join_paths, load_paths from .paths import simplify_paths, sort_paths, join_paths, load_paths
from .planner import Planner from .planner import Planner
from .turtle import Turtle from .turtle import Turtle

53
axi/lindenmayer.py Normal file
View File

@ -0,0 +1,53 @@
import random
import re
from math import sin, cos, radians
from .drawing import Drawing
class LSystem(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 steps(self, value, iterations):
for i in range(iterations):
value = self.step(value)
return value
def run(self, start, iterations, angle=None):
program = self.steps(start, iterations)
angle = angle and radians(angle)
state = (0.0, 0.0, 0.0)
stack = []
paths = []
point = (0.0, 0.0)
for instruction in program:
x, y, a = state
if instruction == '-':
a -= angle
elif instruction == '+':
a += angle
elif instruction == '[':
stack.append(state)
elif instruction == ']':
x, y, a = stack.pop()
point = (x, y)
else:
x += cos(a)
y += sin(a)
if paths and point == paths[-1][-1]:
paths[-1].append((x, y))
else:
paths.append([point, (x, y)])
point = (x, y)
state = (x, y, a)
return Drawing(paths)

21
examples/lindenmayer.py Normal file
View File

@ -0,0 +1,21 @@
import axi
def main():
system = axi.LSystem({
'A': 'A-B--B+A++AA+B-',
'B': '+A-BB--B-A++A+B',
})
d = system.run('A', 5, 60)
# system = axi.LSystem({
# 'X': 'F-[[X]+X]+F[+FX]-X',
# 'F': 'FF',
# })
# d = system.run('X', 6, 20)
d = d.rotate_and_scale_to_fit(12, 8.5, step=90)
# d = d.sort_paths()
# d = d.join_paths(0.015)
d.render().write_to_png('out.png')
axi.draw(d)
if __name__ == '__main__':
main()