Dragon Curve

In this example, we use turtle graphics to generate fractals.

image0

The curve is generated from a self-similar sequence of left and right turns. The basic pattern is :

dragon(0) -> R

dragon(1) -> dragon(0) + R + inverse(dragon(0) -> RRL

dragon(2) -> dragon(0) + R + inverse(dragon(0) -> RRL

and so on. You find a detailed description on Dragon Curve (Wikipedia)

import numpy as np
from PIL import Image

LEFT, UP, RIGHT, DOWN = range(4)


def left(direction):
    """rotates the direction counter-clockwise"""
    return (direction + 3) % 4


def right(direction):
    """rotates the direction clockwise"""
    return (direction + 1) % 4


def forward(a, pos, dist, direction, color=0):
    """draws a line on the canvas"""
    x, y = pos
    if direction == RIGHT:
        a[y, x:x+dist] = color
        pos = x + dist, y
    elif direction == LEFT:
        a[y, x-dist:x] = color
        pos = x - dist, y
    elif direction == UP:
        a[y-dist:y, x] = color
        pos = x, y - dist
    elif direction == DOWN:
        a[y:y+dist, x] = color
        pos = x, y + dist
    return pos


def draw_sequence(a, sequence, pos, size, direction, color):
    """draws a sequence of L and R characters"""
    for char in sequence:
        pos = forward(a, pos, size, direction, color)
        if char == 'R':
            direction = right(direction)
        else:
            direction = left(direction)
    pos = forward(a, pos, size, direction, color)


def invert(seq):
    return ''.join(['L' if char == 'R' else 'R' for char in seq])


def dragon(fwd, depth):
    if depth == 0:
        return fwd
    else:
        bwd = invert(reversed(fwd))
        return dragon(fwd + 'R' + bwd, depth-1)


a = np.zeros((600, 850, 3), dtype=np.uint8)
lightblue = (0, 128, 255)

seq = dragon('R', 12)
print(seq)

draw_sequence(a, seq,
              pos=(500, 150),
              size=4,
              direction=UP,
              color=lightblue)

im = Image.fromarray(a)
im.save('dragon.png')

Hints

  • generate the curve for a small depth first

  • if the size parameter is too big, the program will crash because it reaches the array boundaries.


Challenge

Try the following self-similar sequence:

:::text
seq(0) -> LRRL
seq(1) -> seq(0) + L + seq(0) + R + seq(0) + R + seq(0) + L + seq(0)
...