pythonmatplotlibrecursionpython-turtlehilbert-curve

In the Hilbert Curve, How can I change the library turtle from to matplotlib?


I dont really know how can be solved keeping the recursion, I was studying the turtle library but in the asignature they ask for use matplotlib so I am not really sure about how take it

from turtle import Turtle


def hilbert_curve(turtle, A, parity, n):

    if n == 1:
        hilbert_curve_draw(turtle, A, parity)
        
    else:
        turtle.right(parity * 90)
        hilbert_curve(turtle, A, - parity, n - 1)
        
        turtle.forward(A)
        turtle.left(parity * 90)
        hilbert_curve(turtle, A, parity, n - 1)
        
        turtle.forward(A)
        hilbert_curve(turtle, A, parity, n - 1)
        turtle.left(parity * 90)
        
        turtle.forward(A)
        hilbert_curve(turtle, A, - parity, n - 1)
        turtle.right(parity * 90)


def hilbert_curve_draw(turtle, A, parity):
    turtle.right(parity * 90)
    turtle.forward(A)
    turtle.left(parity * 90)
    turtle.forward(A)
    turtle.left(parity * 90)
    turtle.forward(A)
    turtle.right(parity * 90)
    
yertle = Turtle()

yertle.hideturtle() 
yertle.penup() 
yertle.goto(-200, 200)   
yertle.pendown() 
yertle.speed('fastest')
 
hilbert_curve(yertle, 60, 1, 3)

Solution

  • The turtle keeps an internal state with its position and orientation. These can be represented by local variables. The orientation can be a tuple (xdir, ydir) representing a vector with length 1. Turning left would multiply the vector with a rotation matrix. The rotations can be simplified when only vectors with coordinates -1, 0 and 1 are used.

    The code below implements these ideas. To make things a bit more readable, A has been renamed to length and n to levels.

    from matplotlib import pyplot as plt
    
    def turn_left(orient, parity):
        return (orient[1] * parity, -orient[0] * parity)
    
    def turn_right(orient, parity):
        return turn_left(orient, -parity)
    
    def draw_line(x0, y0, orient, length):
        x1 = x0 + orient[0] * length
        y1 = y0 + orient[1] * length
        plt.plot([x0, x1], [y0, y1], color='navy')
        return x1, y1
    
    def hilbert_curve_draw(x, y, length, orient, parity):
        orient = turn_right(orient, parity)
        x, y = draw_line(x, y, orient, length)
        orient = turn_left(orient, parity)
        x, y = draw_line(x, y, orient, length)
        orient = turn_left(orient, parity)
        x, y = draw_line(x, y, orient, length)
        orient = turn_right(orient, parity)
        return x, y, orient
    
    def hilbert_curve(x, y, length, orient, parity, levels):
        if levels == 1:
            x, y, orient = hilbert_curve_draw(x, y, length, orient, parity)
        else:
            orient = turn_right(orient, parity)
            x, y, orient = hilbert_curve(x, y, length, orient, - parity, levels - 1)
    
            x, y = draw_line(x, y, orient, length)
            orient = turn_left(orient, parity)
            x, y, orient = hilbert_curve(x, y, length, orient, parity, levels - 1)
    
            x, y = draw_line(x, y, orient, length)
            x, y, orient = hilbert_curve(x, y, length, orient, parity, levels - 1)
            orient = turn_left(orient, parity)
    
            x, y = draw_line(x, y, orient, length)
            x, y, orient = hilbert_curve(x, y, length, orient, - parity, levels - 1)
            orient = turn_right(orient, parity)
        return x, y, orient
    
    hilbert_curve(x=-200, y=200, length=5, orient=(1, 0), parity=1, levels=5)
    plt.axis('equal') # same lengths in x and y direction
    plt.show()
    

    hilbert curve with matplotlib