Setting a Course with Absolute Headings

Objective: Setting a Course with Absolute Headings

Welcome to Setting a Course: Absolute Turtle Headings!

Our objective is to create a Python script using Turtle graphics that demonstrates the use of turtle.setheading().

You will make the turtle draw three short lines, each facing a different absolute direction (East, North, West) using setheading.

This will help you understand how setheading controls the turtle's orientation independently of its previous direction, contrasting with relative turns like left() or right().

Check Spec: See the Failing Tests

Before we start coding, let's run the tests to see the current state and confirm the engineering specification.

Run pytest in your terminal.

You should see output indicating that the test designed to check the sequence of turtle commands is failing. This is expected because we haven't implemented the drawing logic yet.

Test Results:

  • test_draw_lines_with_setheading_sequence

Implement: Draw Lines with setheading

Now, let's implement the solution by following the TODO comments in the main.py file.

Your task is to add the necessary turtle commands within the draw_lines_with_setheading function to draw the three lines as described in the objective and the function's docstring.

Remember to use turtle.setheading() to set the direction and turtle.forward() to draw the lines.

Step by step checklist:

  1. Set the turtle's heading to 0 degrees (East) and move it forward by 50 pixels.
  2. Set the turtle's heading to 90 degrees (North) and move it forward by 50 pixels.
  3. Set the turtle's heading to 180 degrees (West) and move it forward by 50 pixels.

The following documentation sections are going to be helpful:

    1. Controlling Turtle's Direction: Absolute Headings
    1. Quick Reference: Key Turtle & Math Functions

Validate: Run the Tests Again

You've added the code to draw the lines using setheading.

Now, let's run pytest again to validate your implementation against the test suite.

If your code correctly sets the headings and draws the lines in the specified order and lengths, the test should now pass.

Run pytest in your terminal.

Test Results:

  • test_draw_lines_with_setheading_sequence All tests passed!

Documentation

Python Turtle & Generative Art: Key Concepts

This document provides a quick reference for the Python concepts and turtle library commands used in the Generative Techniques blueprint.

1. Controlling Turtle's Direction: Absolute Headings

The turtle's heading determines the direction it faces.

  • turtle.setheading(angle): Sets the turtle's orientation to an absolute angle.
    • 0 degrees: East (right)
    • 90 degrees: North (up)
    • 180 degrees: West (left)
    • 270 degrees: South (down) This is different from turtle.left() or turtle.right(), which turn the turtle relative to its current direction.
import turtle
t = turtle.Turtle()

# Face East and draw
t.setheading(0)
t.forward(50)

# Face North and draw
t.setheading(90)
t.forward(50)

# Face West and draw
t.setheading(180)
t.forward(50)

Diagram showing a turtle at the origin with arrows indicating 0, 90, 180, 270 degrees and their corresponding directions (East, North, West, South).

2. Moving the Turtle: Translation

Translation involves moving a shape from one position to another without changing its orientation or size.

  • turtle.penup(): Lifts the pen, so the turtle moves without drawing.
  • turtle.goto(x, y): Moves the turtle to an absolute position (x, y) on the screen. The center of the screen is (0,0).
  • turtle.pendown(): Puts the pen down, so the turtle draws when it moves.
  • turtle.home(): Moves the turtle to the origin (0,0) and sets its heading to 0 degrees (East). Useful for resetting position.
import turtle
t = turtle.Turtle()

def draw_square(size):
    for _ in range(4):
        t.forward(size)
        t.left(90)

# Draw a square at the origin
draw_square(50)

# Translate and draw another square
t.penup()
t.goto(100, 50) # Move to new position
t.pendown()
draw_square(50)

# Reset position and orientation
t.penup()
t.home()
t.pendown()

GIF showing a square being drawn, then the turtle (pen up) moving to a new location, and an identical square being drawn there.

3. Resizing Shapes: Scaling

Scaling changes the size of a shape. This can be achieved by passing a size-modifying parameter to a drawing function.

  • Define a drawing function that accepts a size parameter.
  • Call the function with different size values to draw scaled versions of the shape.
import turtle
t = turtle.Turtle()

def draw_triangle(side_length):
    for _ in range(3): # Equilateral triangle
        t.forward(side_length)
        t.left(120)

# Draw a small triangle
draw_triangle(50)

# Reset position (optional, for clarity if drawing from same origin)
t.penup()
t.home() # Go to (0,0), face East
t.pendown()

# Draw a larger triangle
draw_triangle(100)

Image showing two equilateral triangles, one small and one large, both drawn from the same origin point (0,0). The smaller triangle is inside the larger one.

4. Rotation

4.1. Basic Rotation with Turtle Heading

For simple rotations where the shape is drawn relative to the turtle's current orientation:

  • Use turtle.setheading(angle) to set the turtle's absolute orientation before drawing.
  • Alternatively, use turtle.left(angle) or turtle.right(angle) for relative turns.
import turtle
t = turtle.Turtle()

def draw_rectangle(width, height):
    for _ in range(2):
        t.forward(width)
        t.left(90)
        t.forward(height)
        t.left(90)

# Draw a rectangle
t.setheading(0) # Base along x-axis (East)
draw_rectangle(100, 50)

# Reset, rotate, and draw again
t.penup()
t.goto(0,0)
t.pendown()
t.setheading(270) # Rotated 90 degrees clockwise (or -90)
draw_rectangle(100, 50)

Image showing a rectangle drawn horizontally (heading 0°), and an identical rectangle rotated 90 degrees clockwise (heading 270°), both originating from the same point.

4.2. Advanced Rotation with Trigonometry

For precise rotation of points around an origin (typically (0,0)):

  • Import the math module: import math
  • Convert degrees to radians: math.radians(degrees) (Trigonometric functions in math use radians).
  • Use math.cos(radians) and math.sin(radians) to calculate coordinates.
  • Rotation Formulas (for counter-clockwise rotation of point (x, y) around origin (0,0) by angle_rad):
    • new_x = x * math.cos(angle_rad) - y * math.sin(angle_rad)
    • new_y = x * math.sin(angle_rad) + y * math.cos(angle_rad)
import math

# Original point
x1, y1 = 100, 0
angle_deg = 60

# Convert angle to radians
angle_rad = math.radians(angle_deg)

# Calculate new coordinates
x2 = x1 * math.cos(angle_rad) - y1 * math.sin(angle_rad)
y2 = x1 * math.sin(angle_rad) + y1 * math.cos(angle_rad)

print(f"Original: ({x1}, {y1})")
print(f"Rotated by {angle_deg} degrees: ({x2}, {y2})")

Diagram showing a 2D coordinate plane with a point P and its rotation P' around the origin, illustrating the trigonometric relationship.

5. Building Blocks: Functions

Functions help organize code, make it reusable, and improve readability.

  • Defining a function:
    def function_name(parameter1, parameter2):
        # code block
        # ...
        return result # Optional: sends a value back
    
  • Functions that return values: Use the return statement to send a result back to the part of the code that called the function.
  • Calling a function: Use the function name followed by parentheses (), providing arguments if the function has parameters.
def calculate_area(length, width):
    """Calculates the area of a rectangle."""
    area = length * width
    return area # Send the calculated area back

def demonstrate_calculation():
    rect_length = 8
    rect_width = 5
    
    # Call the function and store the returned value
    calculated_area = calculate_area(rect_length, rect_width)
    
    # Use the returned value
    print(f"The area is: {calculated_area}") # Output: The area is: 40

6. Artistic Alchemy: Combining Transformations

Combine translation, scaling, and rotation within loops to create complex and interesting patterns.

  1. Create a drawing function for a base element, accepting transformation parameters (offset x, offset y, scale factor, rotation angle).

    # Example: BASE_SIZE = 20
    def draw_transformed_square(t, x_offset, y_offset, scale_factor, rotation_angle):
        t.penup()
        t.goto(x_offset, y_offset) # Translation
        t.setheading(rotation_angle) # Rotation
        t.pendown()
        
        side_length = BASE_SIZE * scale_factor # Scaling
        for _ in range(4):
            t.forward(side_length)
            t.left(90)
        t.penup()
    
  2. Use a loop to call this function multiple times, varying the parameters systematically based on the loop counter.

    import turtle
    # Assume draw_transformed_square and BASE_SIZE are defined
    
    pen = turtle.Turtle()
    pen.speed(0) # Fastest
    
    num_elements = 5
    for i in range(num_elements):
        # Vary parameters based on 'i'
        x = i * 30          # Translate x
        y = i * 20          # Translate y
        scale = 1 + (i * 0.2) # Increase scale
        angle = i * 15        # Increase rotation
    
        draw_transformed_square(pen, x, y, scale, angle)
    

GIF showing a sequence of squares being drawn, each progressively larger, more rotated, and shifted, creating a spiral or fanning pattern.

7. Quick Reference: Key Turtle & Math Functions

  • turtle.Turtle(): Creates a new turtle object.
  • turtle.Screen(): Gets the drawing screen object.
  • turtle.done(): Starts the turtle graphics event loop (keeps window open).
  • turtle.exitonclick(): Closes the window when clicked.
  • turtle.speed(speed): Sets the turtle's speed (0 is fastest).
  • turtle.hideturtle(): Makes the turtle cursor invisible.
  • turtle.pensize(width): Sets the pen thickness.
  • turtle.forward(distance): Moves the turtle forward.
  • turtle.backward(distance): Moves the turtle backward.
  • turtle.left(angle): Turns the turtle left by angle degrees (relative).
  • turtle.right(angle): Turns the turtle right by angle degrees (relative).
  • turtle.setheading(angle): Sets the turtle's absolute orientation (0=East, 90=North, 180=West, 270=South).
  • turtle.penup(): Lifts the pen.
  • turtle.pendown(): Lowers the pen.
  • turtle.goto(x, y): Moves the turtle to absolute coordinates (x, y).
  • turtle.home(): Moves turtle to (0,0) and sets heading to 0.
  • math.radians(degrees): Converts an angle from degrees to radians.
  • math.cos(radians): Returns the cosine of an angle in radians.
  • math.sin(radians): Returns the sine of an angle in radians.