
# squareLimit.py
# Andrew Davison, ad@coe.psu.ac.th, April 2025
'''
  Creation of Escher's Square Limit (1964):
    https://uploads3.wikiart.org/images/m-c-escher/square-limit.jpg!Large.jpg

  Implements the code in the "Decomposing the woodcut" section of
    "Programming with Escher"
    Massimo Santini
    https://mapio.github.io/programming-with-escher/
'''

from matplotlib import pyplot as plt
from Tile import *


def side(n):
  # image structuring on a side
  if n == 0: 
    return blank
  else: 
    return quartet(side(n-1), side(n-1), rot(f3), f3)


def corner(n):
  # image structuring at a corner
  if n == 0:
    return blank
  else:
    return quartet(corner(n-1), side(n-1), rot(side(n-1)), f4)


def squarelimit(n):
  return nonet(   # 3 x 3 grid made of
    corner(n),             side(n),  rot(rot(rot(corner(n)))), 
    rot(side(n)),                f4,    rot(rot(rot(side(n)))),
    rot(corner(n)), rot(rot(side(n))), rot(rot(corner(n)))
  )


# ---------------------------------

fig, ax=plt.subplots(figsize=(8, 8))
ax.set_aspect('equal')
size = 15
ax.set_xlim(-size, size)
ax.set_ylim(-size, size)
ax.axis('off')

blank = Tile()   # an empty tile
fish = Tile.read('fish')
smallfish = flip(rot45(fish))

# tile of three fish swimming clockwise around the center
f3 = over(fish, over(smallfish, rot(rot(rot(smallfish)))))

# tile of four fish swimming clockwise around the center
f4 = over( over( over(smallfish, rot(smallfish)), 
               rot(rot(smallfish))), 
          rot(rot(rot(smallfish))))

sl = squarelimit(3)

# enlarge the unit square result, and move to be centered
slBig = Tile.transform(sl, Affine2D().\
             translate(-0.5, -0.5).scale(30, 30))
slBig.show(ax)
plt.show()
