PY-1.1-BP5-MQ40

Objective

Let's begin by reviewing our objective.

Create a Python script that defines a point by its coordinates (x=100, y=0) and an angle of rotation (e.g., 45 degrees). The script must use math.sin and math.cos from the math module to calculate and print the new (x', y') coordinates of this point after it is rotated counter-clockwise around the origin (0,0) by the given angle. Ensure angles are converted to radians for math functions.

Check the Specification

Next, we'll run pytest to see the failing tests. This confirms the engineering specification we need to meet.

Run the tests now.

Test Results:

  • test_rotation_logic_and_output

Implement `main.py`

Now, let's build the solution by following the TODO comments in the skeleton code. Each implementation slide covers all TODOs for a single file, referencing the most relevant documentation sections to review for the task.

Open the main.py file and complete the tasks listed below.

Step by step checklist:

  1. Convert the angle in degrees to radians using the appropriate math function and store the result in the specified variable.
  2. Calculate the new x-coordinate using the initial coordinates, the radian angle, and the cosine and sine math functions, storing the result in the specified variable.
  3. Calculate the new y-coordinate using the initial coordinates, the radian angle, and the cosine and sine math functions, storing the result in the specified variable.
  4. Print the calculated new x and y coordinates, ensuring the output string matches the required format exactly.

The following documentation sections are going to be helpful:

  • 4.2. Advanced Rotation with Trigonometry
    1. Quick Reference: Key Turtle & Math Functions

Validate Your Work

With the code in place, let's run the tests again to validate our work.

Run the tests now.

Test Results:

  • test_rotation_logic_and_output 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.