
# affinePoly.py
# Andrew Davison, ad@coe.psu.ac.th, April 2025
'''
  The shape and example operations come from:
    "Elementary Linear Algebra"
    Stephen Andrilli and David Hecker
    Academic Press, 6th ed., 2023
    Section 8.8, 'Computer Graphics'

  Uncomment the example you want to run.

  Similar to transform.py but using matplotlin's
  Affine2D transformations.
    https://matplotlib.org/stable/api/transformations.html#matplotlib.transforms.Affine2D

  Differences:
     * operations are applied left-to-right
     * no built-in reflection operation in Affine2D
     * vertices are not labeled
     * the Affine2D transform is printed
     * example 5 uses Affine2D addition

'''

import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.transforms import Affine2D


def reflect(m):
  ''' Build reflection Affine2D instance using
      the matrix
         a c e
         b d f
         0 0 1
      with from_values(a,b,c,d,e,f)
  '''
  den = 1 + m*m
  return Affine2D.from_values(
     (1-m*m)/den, 2*m/den, 2*m/den, (m*m-1)/den,
     0, 0)



_, ax = plt.subplots()
axSize = 25    # 15 or 25
ax.set_xlim(0, axSize)
ax.set_ylim(0, axSize)
ax.set_aspect('equal')
ax.grid(True)

# a "knee" shape
coords = [(8,6),(8,8),(6,10),(8,12),(10,10),(10,6)]
poly = Polygon(coords, closed=True, 
                 color='skyblue', alpha=0.7)
'''
# example 1
title = "Original shape"
trfm = Affine2D()
'''

'''
# example 2
title = "rotate 90 degs around (12,6)"
trfm = Affine2D().translate(-12, -6). \
            rotate_deg(90).translate(12, 6)
   # need to add left-to-right
'''

'''
# example 3
title = "reflect around y = -3x+30"
trfm = Affine2D().translate(0, -30) + \
       reflect(-3) + \
       Affine2D().translate(0, 30)
'''

'''
# example 4
title = "scale by (0.5,4) around (6,10)"
trfm = Affine2D().translate(-6,-10). \
           scale(0.5, 4).translate(6,10)
'''

# example 5
title = "rotate 300 degs around (8,10), then\n" + \
        "reflect around y = -0.5x + 20"
trfm = Affine2D().translate(-8, -10). \
            rotate_deg(300).translate(8, 10) + \
       Affine2D().translate(0, -20) + \
       reflect(-0.5) + \
       Affine2D().translate(0, 20)
  # Affine2D objects can be added to compose transforms


print(trfm)  # the resulting Affine2D transform

poly.set_transform(trfm + ax.transData) # add axis offset
ax.add_patch(poly)
plt.title(title)
plt.show()
