Skip to content

Shear and matrices

Shear and matrices

Run it here, in your browser

Three chequerboards: one leaning to the right, one climbing to the right, and one rotated and stretched with a single matrix. A red circle ignores the transform.

How it works

  • f.shear_x() slants everything drawn afterwards sideways. f.shear_y() slants it up and down. Both take degrees.
  • f.apply_matrix() multiplies in any transform at once. The third board turns and stretches in one go.
  • Its six numbers are a, b, c and d, which turn and stretch, then the two that move the board.
  • f.reset_matrix() forgets every transform inside the block, so the circle uses plain window coordinates.
  • Each board sits in a with f.saved_state(): block, so one board's transform does not touch the next.

Make it yours

  • Change the 25 in f.shear_x(25): try 45, or a negative number.
  • Change the 1.4 in f.apply_matrix(): it is the sideways stretch. 1.0 means no stretch.
  • Change the angle in math.radians(20) to 45 and see the third board turn.
  • Make the board bigger: checker(12, 8) in place of checker() draws a 12 by 12 board of 8 pixel cells.
  • Add a fourth board that uses f.shear_x() and f.shear_y() together.

The code

Copy it into a file and run it.

"""Shear and matrices

Three chequerboards: one leaning to the right, one climbing to the right, and one rotated and
stretched with a single matrix. A red circle ignores the transform.

How it works:
- f.shear_x() slants everything drawn afterwards sideways. f.shear_y() slants it up and down. Both
  take degrees.
- f.apply_matrix() multiplies in any transform at once. The third board turns and stretches in one
  go.
- Its six numbers are a, b, c and d, which turn and stretch, then the two that move the board.
- f.reset_matrix() forgets every transform inside the block, so the circle uses plain window
  coordinates.
- Each board sits in a with f.saved_state(): block, so one board's transform does not touch the
  next.

Make it yours:
- Change the 25 in f.shear_x(25): try 45, or a negative number.
- Change the 1.4 in f.apply_matrix(): it is the sideways stretch. 1.0 means no stretch.
- Change the angle in math.radians(20) to 45 and see the third board turn.
- Make the board bigger: checker(12, 8) in place of checker() draws a 12 by 12 board of 8 pixel cells.
- Add a fourth board that uses f.shear_x() and f.shear_y() together.
"""
import math

import funground as f


def setup():
    f.size(640, 400)


def checker(size=8, cell=12):
    for row in range(size):
        for col in range(size):
            f.fill("navy" if (row + col) % 2 else "gold")
            f.rect(col * cell, row * cell, cell, cell)


def draw():
    f.background("white")
    f.no_stroke()
    with f.saved_state():
        f.translate(40, 60)
        f.shear_x(25)                     # leans to the right
        checker()
    with f.saved_state():
        f.translate(230, 40)
        f.shear_y(20)                     # climbs to the right
        checker()
    with f.saved_state():
        a = math.radians(20)              # rotate by 20 degrees and stretch sideways, in one matrix
        f.apply_matrix(1.4 * math.cos(a), math.sin(a), -1.4 * math.sin(a), math.cos(a), 470, 60)
        checker()
        with f.saved_state():
            f.reset_matrix()              # back to plain window coordinates
            f.fill("tomato")
            f.circle(320, 330, 60)


f.run()

View on GitHub ยท Back to the gallery