Skip to content

Instantly share code, notes, and snippets.

@sli
Last active October 26, 2016 00:01
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 sli/1d0b76773658ebb5188237047c7776d5 to your computer and use it in GitHub Desktop.
Save sli/1d0b76773658ebb5188237047c7776d5 to your computer and use it in GitHub Desktop.
A generic L-System renderer that uses Turtle.
'''
A generic L-System renderer that uses Turtle. Try some of these examples:
Lace: $ python lsystem.py -i 6 -a 30 -x W -r W=+++X--F--ZFX+;X=---W++F++YFW-;Y=+ZFX--F--Z+++;Z=-YFW++F++Y--- -l 5 -s -50,-200,90
Dragon Curve: $ python lsystem.py -i 10 -a 90 -x FX -r X=X+YF;Y=FX-Y
Fractal Plant: $ python lsystem.py -i 6 -a 25 -r X=C0F-[C2[X]+C3X]+C1F[C3+FX]-X;F=FF -l 5 -s -100,-200,65
Koch Snowflake: $ python lsystem.py -i 4 -a 60 -x F++F++F -r F=F-F++F-F -l 5 -s -200,-150,0
Kevs Wispy Tree: $ python lsystem.py -i 5 -a 25 -x FX -r F=C0FF-[C1-F+F]+[C2+F-F];X=C0FF+[C1+F]+[C3-F] -s 0,-200,90 -l 5
Sierpinski Carpet: $ python lsystem.py -i 4 -a 90 -x F -r F=F+F-F-F-G+F+F+F-F;G=GGG -l 5 -s 0,-150,90 -g
Sierpinski Triangle: $ python lsystem.py -i 6 -a 120 -x F-G-G -r F=F-G+F+G-F;G=GG -l 5 -s 100,100,-90 -g
Joined Cross Curves: $ python lsystem.py -i 3 -a 90 -x XYXYXYX+XYXYXYX+XYXYXYX+XYXYXYX -r F=;X=FX+FX+FXFY-FY-;Y=+FX+FXFY-FY-FY -l 5 -s -200,-200,0
Sierpinski Median Curve: $ python lsystem.py -i 8 -a 45 -x L--F--L--F -r L=+R-F-R+;R=-L+F+L- -l 5 -s -100,0,0
Sierpinkski Triangle (w/curves): $ python lsystem.py -i 7 -a 60 -x F -r F=G-F-G;G=F+G+F -s 150,-100,180 -l 3 -g
'''
import click
import turtle
def next_generation(previous_generation: str, constants: list, rules: dict) -> str:
return ''.join([translate(i, constants, rules) for i in previous_generation])
def draw_generation(instructions: str, angle: int=60,
length: int=1, start: tuple=(0, 0),
start_angle: int=0, drawg: bool=False,
fill: bool=False):
positions = []
turtle.speed('fastest')
turtle.penup()
turtle.setpos(start)
turtle.setheading(start_angle)
turtle.pendown()
if fill is True:
turtle.begin_fill()
for i in instructions:
if i == 'F' or (i == 'G' and drawg is True):
turtle.forward(length)
elif i == 'G' and drawg is False:
turtle.penup()
turtle.forward(length)
turtle.pendown()
elif i == '+':
turtle.left(angle)
elif i == '-':
turtle.right(angle)
elif i == '[':
positions.append((turtle.heading(), turtle.pos()))
elif i == ']':
p = positions.pop()
turtle.penup()
turtle.setheading(p[0])
turtle.setpos(p[1])
turtle.pendown()
if fill is True:
turtle.end_fill()
print('l-system render completed')
turtle.done()
def translate(instruction: str, constants: list, rules: dict) -> str:
if instruction in rules and instruction not in constants:
return rules[instruction]
return instruction
def to_rules(rules: list) -> dict:
return {rule.split('=')[0]: rule.split('=')[1] for rule in rules}
@click.command()
@click.option('--iterations', '-i', default=3,
help='Iterations (generations)')
@click.option('--angle', '-a', default=90, help='Angle step')
@click.option('--constants', '-c', default='', help='Constants (Ex: X;Y)')
@click.option('--axiom', '-x', default='X', help='Axiom (Ex: X+F)')
@click.option('--rules', '-r', default='X=-YF+XFX+FY-;Y=+XF-YFY-FX+',
help='Rules (Ex: X=-YF+XFX+FY-;Y=+XF-YFY-FX+)')
@click.option('--length', '-l', default=10, help='Draw step')
@click.option('--start', '-s', default='0,0,0',
help='Starting point and angle (Ex: 0,0,90)')
@click.option('--drawg', '-g', is_flag=True, default=False,
help='Enable drawing on G instruction')
@click.option('--fill', '-f', is_flag=True, default=False,
help='Enable fill')
@click.option('--verbose', '-v', is_flag=True, default=False,
help='Display each generation')
def lsystem(iterations, angle, constants, axiom,
rules, length, start, drawg, fill, verbose):
constants = constants.split(';')
rules = to_rules(rules.split(';'))
start = tuple((int(p) for p in start.split(',')))
start_position = start[:2]
start_angle = start[2]
current_generation = axiom
for n in range(iterations):
current_generation = next_generation(current_generation, constants, rules)
if verbose is True:
print('Generation {}: {}'.format(n, current_generation))
draw_generation(current_generation, angle, length,
start_position, start_angle, drawg, fill)
if __name__ == '__main__':
lsystem()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment