Last active
October 26, 2016 00:01
-
-
Save sli/1d0b76773658ebb5188237047c7776d5 to your computer and use it in GitHub Desktop.
A generic L-System renderer that uses Turtle.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
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