Issue: Creating Pythagoras Tree

125 Views Asked by At

Symmetric Pythagorean Tree

My code isn't able to produce a symmetric pythagorean tree as shown above.

from turtle import *
from math import sin, cos


def main():
    t = Turtle()  # Initiate turtle to t
    t.speed(5)  # Set turtle speed

    window = Screen()  # Initialize window to draw
    window.bgcolor('white')
    window.tracer(True)

    # -- Parameters --
    level = 3  # Set the degree here
    length = 200
    a = 45  # Set the angle "alpha" here, must be less than 90
    points = [Vec2D(0, 0), Vec2D(0, length), Vec2D(length, length), Vec2D(length, 0)]

    pythTree(t, length, level, a, points)

    # Program ends
    window.exitonclick()


def pythTree(t, length, level: int, angle: int, points) -> None:

    if level > 0:

        drawSquare(t, points)

        # Calculate the lengths of the next two squares
        lengths = scaleLength(length, angle)
        # Calculate the position of the squares in the recursive call

        # -- Recursive Calls --
        pythTree(t, lengths[0], level - 1, angle, [x.rotate(angle) * cos(angle) for x in points])  # Left Side BC

        pythTree(t, lengths[1], level - 1, angle, [x.rotate(-angle) * sin(angle) for x in points])  # Right Side AC


def drawSquare(t, points) -> None:

    t.begin_fill()
    for point in points:
        t.goto(point)
    t.goto(points[0])
    t.end_fill()
    update()


def scaleLength(length, angle: int) -> tuple[int | float, int | float]:
    # LEFT SIDE: BC
    BC = cos(angle) * length
    # RIGHT SIDE: AC
    AC = sin(angle) * length
    return BC, AC


if __name__ == '__main__':
    main()

The squares are scaled (using cos / sin) and moved using the list comprehension.

However I couldn't manage to move the rotated and scaled squares to their proper position.

I tried:

  1. [x.rotate(angle) * cos(angle) + points[1] for x in points] to move the square to its proper position but it breaks past two levels.
2

There are 2 best solutions below

0
Michael Sohnen On

This isn't exactly the right way to use stackoverflow, but instead of giving a full answer, I'll just help you start debugging

First, I turned off the fill command so you can see the outlines instead Then I removed the second called to the tree drawing command. It's better off to start by debugging just one call

This is what I got enter image description here

So it appears you are on the right track. You just need calculate how tall each square is in the y direction and offset by that

Good luck debugging and you can comment with more questions as you go along

0
cdlane On

Similar to @MichaelSohnen, instead of giving a full answer, I'm only going to show a solution for the simplest 45 degree case and leave you to generalize it for any angle. But instead of turning off the fill command and using only outlines, I'm going to eliminate outlines by stamping out a solution instead of drawing it:

from turtle import Screen, Turtle

LENGTH = 100
CURSOR_SIZE = 20

def scaleLength(length):
    return (2 * (length/2)**2) ** 0.5

def drawSquare(t, length):
    t.shapesize(length / CURSOR_SIZE)
    t.stamp()

def pythTree(t, length, level):
    if level < 1:
        return

    drawSquare(t, length)

    if level < 2:
        return

    scaled_length = scaleLength(length)

    t.forward(length)
    t.left(90)
    t.forward(length/2)
    t.right(45)

    pythTree(t, scaled_length, level - 1)

    t.right(135)
    t.forward(length)
    t.left(45)

    pythTree(t, scaled_length, level - 1)

    t.left(135)
    t.forward(length/2)
    t.right(90)
    t.backward(length)

screen = Screen()
screen.tracer(False)

turtle = Turtle()
turtle.hideturtle()
turtle.setheading(90)
turtle.shape('square')
turtle.penup()

pythTree(turtle, LENGTH, 12)

screen.update()
screen.exitonclick()

Stamping allows me to draw with respect to where the center of the square is located, rather than any specific corner.

One of the key things to remember when drawing a recursive figure is that, when it returns, the recursive call has to leave the cursor in the same location and orientation as when it was called, i.e. the caller needs to be able to continue from where it left off, drawing-wise.

enter image description here