Homework 2: Affine Transforms#

Deadline: In order to successfully complete this assignment, you must follow all the instructions in this notebook and upload your edited ipynb file to D2L with your answers on or before Friday, February 17 at 11:59pm ET.

You may collaborate with other students in this course. However, you may only share ideas with each other, not code or answers.

Also, note that your section’s TA will run your code cells in order (top to bottom) in order to grade your homework submission. So please make sure your code cells work as you intend when you run them in order.

BIG HINT: Read the entire homework before starting.

# Here are some libraries you may need to use
%matplotlib inline
import matplotlib.pylab as plt

import numpy as np
import sympy as sym

1. (26 pts) Linear Transform#

In class we discussed several linear transformations: rotation, shearing, scaling and translation. Consider a two-dimensional case. Rotation, shearing and scaling can be represented by \(2\times2\) matrices:

\[\begin{split}\begin{bmatrix}x'\\y'\end{bmatrix}=\begin{bmatrix}m_{11}&m_{12}\\m_{21}&m_{22}\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}\end{split}\]

where \(x,y\) are the original coordinates and \(x',y'\) are the transformed ones.

Translation is additive, however, we can also represent it with a matrix multiplication if we enlarge the dimension of vectors by 1 and represent the most generic matrix for any of the four transformations as:

\[\begin{split}\begin{bmatrix}x'\\y'\\1\end{bmatrix}=\begin{bmatrix}m_{11}&m_{12}&m_{13}\\m_{21}&m_{22}&m_{23}\\ 0&0&1\end{bmatrix}\begin{bmatrix}x\\y\\1\end{bmatrix}\end{split}\]

where \(x,y\) are the original coordinates and \(x',y'\) are the transformed ones. In this case the upper left \(2\times2\) block represents rotation, sharing and scaling, while the third column represents translation.

Let us consider a square with its vertices located at \((0,0)\), \((-3,0)\), \((-3,3)\) and \((0,3)\) and find the transformation that maps it onto a diamond with vertices at \((1,0)\), \((0,1)\), \((1,2)\) and \((2,1)\).

# original points
x  = [ -3, -3, 0, 0, -3 ]
y  = [ 0, 3, 3, 0, 0 ]
# transformed points
xp = [ 0, 1, 2, 1, 0 ]
yp = [ 1, 2, 1, 0, 1 ]

# plot
plt.plot( x, y, "*-" )    # square
plt.plot( xp, yp, "*-" )  # diamond
plt.axis( [-5.75,5.75,-3,6])

QUESTION 1a: (5 pts) We need at least three points to determine the transformation matrix \(M\). Take the following three vertices and assume that the transformation \(M\) maps:

  • \((0,0)\) to \((1,0)\),

  • \((-3,0)\) to \((0,1)\), and

  • \((-3,3)\) to \((1,2)\)

(find these points on the graph to understand what is going on).

Write down a system of \(6\) equations for the \(6\) unknowns in the matrix \(M\). Put down the system in the row form.

Put your answer here

QUESTION 1b: (8 pts) Despite that the system of equations you wrote in 1a is \(6\times6\), it is easy to solve with pen and paper. Solve the system with pen and paper and outline what substitutions you made to find the answer. Write down the final answer as \(3\times3\) matrix.

Put an outline of what substitutions you made to find the answer here.

Also, edit the \(3 \times 3\) matrix below with your final answer:

\[\begin{split} \begin{bmatrix} ? & ? & ?\\ ? & ? & ?\\ ? & ? & ? \end{bmatrix} \end{split}\]

QUESTION 1c: (8 pts) Now use Python to find the 6 values in the matrix \(M\) based on the above system of equations, and store them in a \(3\times 3\) numpy.matrix varibale named M. (Replace 0 with your solution below, do not forget to add the third row as 0 0 1.)

##Edit this cell to answer the question.

M = 0
from answercheck import checkanswer
checkanswer.matrix(M,'24c658ad7b62fa932b3ebd8d381f2905');

QUESTION 1d: (5 pts) Now use matrix M that you just constructed in Python to calculate where the fourth vertex \((0,3)\) will move after the transform. Store the resulting vector of the form \((x',y',1)\) in variable V. What result do you expect based on the figure at the beginning of this exercise?

##Edit this cell to answer the question.

V = 0

Put your answer here

from answercheck import checkanswer
checkanswer.vector(V,'359886fa5fb3b5423ef5ff67735b2f5b')

2. (28 pts) Combined Transforms#

In this problem, we will construct the transformation that we solved for in the previous problem from rotation, scaling and translation.

QUESTION 2a: (4 pts) First, we need to make the center of the square (the blue square) coincide with the origin (the orange square). Construct a translation matrix that translates the center of the square, point

\[\left(-\frac{3}{2}, \frac{3}{2}\right) \mapsto (0,0).\]

Store it in Python variable T1 as \(3\times3\) matrix.

To help you visualize the transformation consider the figure below.

# original points
x  = [ -3, -3, 0, 0, -3 ]
y  = [ 0, 3, 3, 0, 0 ]
# transformed points
xp = [-1.5, -1.5,  1.5,  1.5, -1.5]
yp = [-1.5,  1.5,  1.5, -1.5, -1.5]

# plot
plt.plot( x, y, "*-" )    # square
plt.plot( xp, yp, "*-" )  # diamond
plt.axis( [-5.75,5.75,-3,6])
##Edit this cell to answer the question.

T1=0
print(T1)
from answercheck import checkanswer
checkanswer.matrix(T1,'24b27fed6d539cf4be51cd56a95e8100');

QUESTION 2b: (4 pts) Now, we can rotate the square (the blue square) around the origin by 45 degrees clockwise (the orange square). Construct a rotation matrix that performs a rotation by 45 degrees clockwise and store it in Python variable R as \(3\times3\) matrix.

To help you visualize the transformation consider the figure below.

# original points
x = [-1.5, -1.5,  1.5,  1.5, -1.5]
y = [-1.5,  1.5,  1.5, -1.5, -1.5]
# transformed points
s = 3/np.sqrt(2)
xp = [-s, 0, s, 0, -s]
yp = [0, s, 0, -s, 0]

# plot
plt.plot( x, y, "*-", color='#1f77b4' )
plt.plot( xp, yp, "*-", color='#ff7f0e' )
plt.axis( [-5.75,5.75,-3,6])
##Edit this cell to answer the question.

R=0
print(R)
from answercheck import checkanswer
checkanswer.matrix(R,'96491aabf1a23f1090aeea4596f579df');

QUESTION 2c: (4 pts) Next, we need to chrink the rotated square (the blue square) by a factor of $\(\frac{3}{\sqrt{2}}\)\( (the orange square). The reason is the blue square has a side length \)3\(, while the orange square has a sile length of \)\sqrt{2}$. Hence

\[ \frac{\text{blue length}}{\text{factor}} = \text{orange length}\qquad\Longrightarrow \qquad \frac{3}{\frac{3}{\sqrt{2}}} = \sqrt{2}. \]

In other words, we scale the blue square by a factor of \(\frac{\sqrt{2}}{3}\).

Construct a scaling matrix that scales along the \(x\) and \(y\) axis by \(\frac{\sqrt{2}}{3}\) and store it in Python variable S.

To help you visualize the transformation consider the figure below.

# original points
s = 3/np.sqrt(2)
x = [-s, 0, s, 0, -s]
y = [0, s, 0, -s, 0]
# transformed points
xp = [-1, 0, 1, 0, -1]
yp = [0, 1, 0, -1, 0]

# plot
plt.plot( x, y, "*-", color='#1f77b4' )
plt.plot( xp, yp, "*-", color='#ff7f0e' )
plt.axis( [-5.75,5.75,-3,6])
##Edit this cell to answer the question.

S=0
print(S)
from answercheck import checkanswer
checkanswer.matrix(S,'b45b98e743d89b2397bfb2ea766cca75');

QUESTION 2d: (4 pts) Our final move is to translate the diamond (the blue square) so that its center is at position \((1,1)\) (the orange square). Construct a translation matrix that translates \((0,0)\) to \((1,1)\) and store it in Python variable T2.

To help you visualize the transformation consider the figure below.

# original points
x = [-1, 0, 1, 0, -1]
y = [0, 1, 0, -1, 0]
# transformed points
xp = [0, 1, 2, 1, 0]
yp = [1, 2, 1, 0, 1]

# plot
plt.plot( x, y, "*-", color='#1f77b4' )
plt.plot( xp, yp, "*-", color='#ff7f0e' )
plt.axis( [-5.75,5.75,-3,6])
##Edit this cell to answer the question.

T2=0
print(T2)
from answercheck import checkanswer
checkanswer.matrix(T2,'312c24e5e5aa4504ce2c9a68689660ec');

QUESTION 2e: (5 pts) We now have the sequence of transformations that turns the square with vertices at \((0,0)\), \((-3,0)\), \((-3,3)\) and \((0,3)\) into a diamond with vertices at \((1,0)\), \((0,1)\), \((1,2)\) and \((2,1)\). They are:

  • translation T1

  • rotation R

  • scaling S

  • translation T2

Calculate the final transformation matrix P as the composition of the above operations and print the result below.

##Edit this cell to answer the question.

P = 0
print(P)
from answercheck import checkanswer
checkanswer.matrix(P,'24c658ad7b62fa932b3ebd8d381f2905');

In what order the matrices need to be multiplied? Does your result coincide with the matrix \(M\) that you calculated in the first problem?

Put your answer here

QUESTION 2f: (7 pts) What would happen if we confuse the order of multiplication? Construct a transformation Z where you multiply the same operations T1, R, S and T2 but in the order opposite to the correct one. Calculate matrix Z and use it to find how the vertices of the square transform in this case. Plot side by side the original square and the geometrical shape achieved by the transformation Z similar to how the square and diamond are plotted in the previous figures.

##Edit this cell to answer the question.

Z = 0
print(Z)
from answercheck import checkanswer
checkanswer.matrix(Z,'670294c1f5ce8ecf79ae1007cde9b9b4');
# Put your plotting code here to have the original and transformed shapes side by side

Is Z the same as P? Explain your results.

Put your answer here


3. (22 pts) Inverse Transform#

Consider now a problem of transforming the diamond back into square. This is achieved by the inverse transform.

QUESTION 3a: (8 pts) Use the rref function in sympy to find the inverse of the transformation P and store it as P_inv. (Hint: you can use numpy.concatenate to join two \(3\times 3\) matrices into one \(3\times 6\) matrix.)

Recall that, if we do Gauss-Jordan process on $\( [P \;|\; I_3] \)\( where \)I_3\( is the \)3\times 3\( identity matrix, then at the end we get \)\( \left[I_3 \;|\; P^{-1}\right] \)$

Note: Call P.evalf(2) to round 1.5000 to 1.5 in your final answer, if \(P\) is a sympy.matrix.

##Edit this cell to answer the question. You only need to find P_inv using the above method, your P_inv should be a sympy matrix 3 by 3

P_inv = 0  # P_inv is sympy.matrix

# keep these two lines for answer checking
P_inv_round = P_inv.evalf(2)
print(P_inv_round)
from answercheck import checkanswer
checkanswer.matrix(P_inv_round,'c6532fc04cd4a5658fe5be2d13945bb0');

QUESTION 3b: (10 pts) Write down the matrices for the inverse transformations of T1, R, S and T2 in QUESTION 2.

For instance, T1 is a translation:

  • by \(3/2\) in \(x\) direction and

  • \(-3/2\) in \(y\) direction,

thus, the inverse is a translation by

  • \(-3/2\) in \(x\) direction and

  • \(3/2\) in \(y\) direction.

Store the results in variables T1_inv, R_inv, S_inv and T2_inv.

##Edit this cell to answer the question.

T1_inv=np.matrix([[1,0,-1],[0,1,1],[0,0,1]])
print(T1_inv)
R_inv=0
print(R_inv)
S_inv=0
print(S_inv)
T2_inv=0
print(T2_inv)

QUESTION 3c: (4 pts) As we know, if \(A\), \(B\), \(C\), \(\dots\) are invertible, we have $\((ABC\dots)^{-1}=\dots C^{-1}B^{-1}A^{-1}.\)\( Based on this rule, use the inverse transformation matrices to construct the inverse of \)P$ and check whether it is the same as you obtained in the previous question. Store the inverse constructed as product in variable P_inv2.

##Edit this cell to answer the question.

P_inv2 = 0
print(P_inv2)
from answercheck import checkanswer
checkanswer.matrix(P_inv2,'c6532fc04cd4a5658fe5be2d13945bb0');

4. (24 pts) Transforms in three spatial dimensions#

In the previous exercises we considered transformations in two spatial dimensions. To accommodate translations we embedded two-dimensional transformations in three-dimensional matrices. Without translations we could have used \(2\times 2\) matrices.

In general, if we write linear transformations on \(\mathbb{R}^n\) that include rotations, reflections, scaling and shearing we need \(n\times n\) matrices. If we also include translation, we need \((n+1)\times(n+1)\) matrices with the last row containing \(0\)’s except of \(1\) on the diagonal.

In this exercise we consider transformations on \(\mathbb{R}^3\), i.e. three-dimensional space without translation. In this case it is enough to work with \(3\times3\) matrices.

QUESTION 4a: (8 pts) Use python code to construct the following three \(3 \times 3\) transformation matrices:

  • Ry: Rotate points about the \(y\)-axis by an angle of degreey\(=45^\circ\)

  • Rz: Rotate points about the \(z\)-axis by an angle of degreez\(=120^\circ\)

  • SH: Shear points in the \(x\)-direction by an amount that is sh\(=2.0\) times the \(y\)-component, i.e., \(x_{\text{new}} = x_{\text{old}}+2.0y_{\text{old}}\)

  • SK: Scale the \(x\)-component of points by a factor of sk\(=1/2\)

Note that by default the direction of rotation about the \(x\), \(y\), or \(z\) axis follows the “right hand rule”. Point your right thumb in the positive direction along the axis of rotation, and the fingers on your right hand will curl in the direction of rotation.

## Finish the code in this cell.
degreey = 45
Ry = 0 

degreez = 120
Rz = 0

sh = 1.0 
SH = 0 

sk = 1/2 
SK = 0 
from answercheck import checkanswer
checkanswer.matrix(Ry,'1ebb1d12d2dc608a6c1cba0111055e36');
checkanswer.matrix(Rz,'15761f70a4ab131cdb2c76e5490e3a32');
checkanswer.matrix(SH,'7e3b2a23b1e34326482a5b5a685fc36e');
checkanswer.matrix(SK,'09f9fcdd1cdcffbfc639ea32ba2abc16');

QUESTION 4b: (4 pts) Combine the four matrices into one transfrom matrix in the way that :

  • shear is applied first,

  • then the scaling.

  • then rotation along \(z\) and

  • then rotation along \(y\),

Store the result in variable M.

### Put your answer here

M = 0
from answercheck import checkanswer
checkanswer.matrix(M,'5b5f7f618c21c65a5970f5a1b49fbf0e');

QUESTION 4c: (8 pts) Calculate the inverse of M and store it in M_inv by using Gauss-Jordan elimination with sympy. Note that your M_inv should be a sympy.Matrix.

### Put your answer here

M_inv = 0
print(M_inv)
from answercheck import checkanswer
checkanswer.matrix(M_inv,'565b0161887b65a11b5145fea597cadc');

QUESTION 4d: (4 pts) Consider a point whose coordinates after the transformation M are \((-1,-1,-1)\). Where was this point before the transformation matrix was applied? Print the result below

### Put your answer here

p = 0
print(p)

Congratulations, we’re done!#