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 11:59pm on Friday October 9th.

BIG HINT: Read the entire homework before starting.

Homework 2: Affine Transforms

Rotating Teapot

In this homework we are going to work with some 3D data in the obj format which is a common file type which mostly consists of a list of 3d points (vertices) and a list of point indexes which form polygons (faces). Some example objects in the obj format can be found at the on this Website with obj files.


1. Downloading 3D obj files

The following code will open the website and download a list names for the available obj files.

from urllib.request import urlopen
import re

url = 'https://people.sc.fsu.edu/~jburkardt/data/obj/'


fid = urlopen(url)

html = fid.readlines()
all_names = []
index = 0
for line in html:
    matches = re.findall('\"\w*\.obj\"',str(line))
    for i in matches:
        if i:
            name = i[1:-1]
            print(f"{index} {name}")
            all_names.append(name)
            index += 1
0 airboat.obj
1 al.obj
2 alfa147.obj
3 babem.obj
4 cessna.obj
5 cube.obj
6 diamond.obj
7 dodecahedron.obj
8 gourd.obj
9 hans.obj
10 humanoid_quad.obj
11 humanoid_tri.obj
12 icosahedron.obj
13 irene.obj
14 john.obj
15 lamp.obj
16 lee.obj
17 magnolia.obj
18 maribel.obj
19 minicooper.obj
20 octahedron.obj
21 power_lines.obj
22 pyramid.obj
23 roi.obj
24 sandal.obj
25 shuttle.obj
26 skyscraper.obj
27 slot_machine.obj
28 symphysis.obj
29 teapot.obj
30 tetrahedron.obj
31 tommygun.obj
32 trumpet.obj
33 violin_case.obj

You can use the following code to download individual files to your current directory:

from urllib.request import urlretrieve, urlopen

filename = all_names[25]
print(filename)
urlretrieve(url+filename, filename);
shuttle.obj

The following function (written with the help of Claudia Chen) reads in the 3D object and stores it as a set of 3D points (vertices) and how the points are connected (faces). NOTE Not all of the files in the above list have been tested with this code, it is possible some of them do not work correctly.

import numpy as np
%matplotlib inline
import matplotlib.pylab as plt

def readobjfile(filename):
    """Simple function to read standard object (obj) files and returns a list
    of verticies and polygon faces (typically triangles)"""
    render_thing = open(filename)
    vertices = []
    faces = []
    for i in render_thing.readlines():
        row = i.strip().split()
        if row:
            if(row[0] == "v"):
                vertices.append(row[1:4])
            elif(row[0] == "f"):
                face = np.array(row[1:], dtype=np.int16)
                face -=1 #adjust to match python index (start counting from zero)
                faces.append(list(face))

    vertices = np.array(vertices, dtype=np.float32)
    
    return vertices, faces

def plotobjdata(vertices, faces):
    '''Plot the obj surface. Note this function does not scale the axis equally so there
    be some visual skew in the data'''
    polys = []
    for i in faces:
        poly = []
        for index in i:
            poly.append(vertices[index])
        polys.append(poly)

    from mpl_toolkits.mplot3d.art3d import Poly3DCollection   
    srf = Poly3DCollection(polys, alpha=0.5, facecolor='#800000')
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter3D(vertices[:,0], vertices[:,1], vertices[:,2]);
    ax.autoscale()
    ax.add_collection3d(srf)
#Read in the data
vertices, faces = readobjfile(filename)
#Plot the object with it's faces
plotobjdata(vertices, faces)

2. Teapot example

**Do This:** (10 pts) Modify the above code to download the teapot example and store the values in verticies and faces.

#either modify the code above or add your code here.
from answercheck import checkanswer
checkanswer.matrix(vertices, '25bcaa0c8991d0d80b7d8ec89baa38c3')
CheckWarning: passed variable is <class 'numpy.ndarray'> and not a numpy.matrix...
    Trying to convert to a array matrix using ```A = np.matrix(A)```.


CheckWarning: passed matrix is float32 and not <class 'numpy.float64'>...
    Trying to convert to float using ```A = A.astype(float)```.


CheckWarning: Matrix contains negative values for zero...
    Converting to positive values of zero using  ```A[A==-0] = 0```.

Testing [[ 3.07022e+00 -1.19730e-01  9.96440e-01]
 [ 5.94202e+00 -1.20200e-02  4.15720e+00]
 [ 6.61402e+00 -6.34300e-02  4.15720e+00]
 [ 5.75911e+00  0.00000e+00  1.66450e+00]
 [ 3.07022e+00 -4.49140e-01  9.29430e-01]
 [ 5.00030e+00 -5.39010e-01  1.31510e+00]
 [ 3.07022e+00 -6.04750e-01  8.72460e-01]
 [ 3.07022e+00 -8.66520e-01  7.30690e-01]
 [ 3.07022e+00 -9.59010e-01  6.50260e-01]
 [ 3.07022e+00 -1.05363e+00  1.63280e-01]
 [ 2.98325e+00 -1.08002e+00 -8.80640e-01]
 [ 6.13032e+00 -1.10002e+00 -1.10694e+00]
 [ 3.73929e+00 -4.33410e+00 -8.76960e-01]
 [ 4.40028e+00 -4.68210e+00 -9.52940e-01]
 [ 3.03825e+00 -4.33410e+00 -8.11320e-01]
 [ 3.18026e+00 -4.55009e+00 -9.21940e-01]
 [ 2.70025e+00 -4.33410e+00 -9.47940e-01]
 [ 8.40210e-01 -2.48005e+00 -1.05031e+00]
 [ 1.20879e+00 -1.06073e+00  2.03820e-01]
 [ 1.20879e+00 -1.05415e+00  4.11070e-01]
 [ 1.20879e+00 -9.58090e-01  6.10370e-01]
 [ 1.20879e+00 -8.75160e-01  6.85960e-01]
 [ 1.20879e+00 -6.21530e-01  8.54700e-01]
 [ 1.20879e+00 -4.67360e-01  9.22280e-01]
 [-4.64909e+00 -1.03959e+00  2.09480e-01]
 [-4.64934e+00 -9.22340e-01  4.32260e-01]
 [-4.64971e+00 -6.52580e-01  7.53550e-01]
 [-4.99990e+00 -1.01254e+00  9.45300e-02]
 [-4.99924e+00 -8.70270e-01  3.47380e-01]
 [-4.99932e+00 -8.02310e-01  4.16130e-01]
 [-4.90671e+00 -6.20190e-01  6.86500e-01]
 [-4.99976e+00 -4.91150e-01  8.05210e-01]
 [-5.56803e+00 -1.19200e-01  5.68690e-01]
 [-5.34912e+00 -8.14180e-01  2.47110e-01]
 [-5.34880e+00 -9.38380e-01 -3.01800e-02]
 [-6.49998e+00 -6.76000e-01 -4.33500e-01]
 [-6.49998e+00 -6.10000e-01 -1.64800e-01]
 [-6.49998e+00 -2.40000e-01  1.09600e-01]
 [-7.64998e+00  0.00000e+00 -6.20000e-01]
 [ 1.20924e+00 -1.08002e+00 -1.32162e+00]
 [ 3.07022e+00  1.19730e-01  9.96440e-01]
 [ 3.09302e+00  4.08000e-02  1.27630e+00]
 [ 6.61402e+00  6.34300e-02  4.15720e+00]
 [ 3.07022e+00  4.49140e-01  9.29430e-01]
 [ 5.00030e+00  5.39010e-01  1.31510e+00]
 [ 3.07022e+00  6.04750e-01  8.72460e-01]
 [ 3.07022e+00  8.66520e-01  7.30690e-01]
 [ 5.00030e+00  1.14902e+00  1.26010e+00]
 [ 3.07022e+00  9.59010e-01  6.50260e-01]
 [ 3.07022e+00  1.05363e+00  4.49900e-01]
 [ 5.00030e+00  1.42803e+00  4.42100e-01]
 [ 3.07022e+00  1.05363e+00  1.63280e-01]
 [ 2.98325e+00  1.08002e+00 -8.80640e-01]
 [ 5.00030e+00  1.30293e+00 -1.25995e+00]
 [ 3.73929e+00  4.33410e+00 -8.76960e-01]
 [ 4.40028e+00  4.68210e+00 -9.52940e-01]
 [ 3.03825e+00  4.33410e+00 -8.11320e-01]
 [ 3.18026e+00  4.55009e+00 -9.21940e-01]
 [ 1.20924e+00  1.08002e+00 -6.36410e-01]
 [ 2.70025e+00  4.33410e+00 -9.47940e-01]
 [ 1.69220e-01  1.99004e+00 -1.06328e+00]
 [ 1.20879e+00  1.06073e+00  2.03820e-01]
 [ 1.20879e+00  1.05415e+00  4.11070e-01]
 [ 1.20879e+00  9.58090e-01  6.10370e-01]
 [ 1.20879e+00  8.75160e-01  6.85960e-01]
 [ 1.20879e+00  6.21530e-01  8.54700e-01]
 [ 1.20879e+00  4.67360e-01  9.22280e-01]
 [-4.64909e+00  1.03959e+00  2.09480e-01]
 [-4.64934e+00  9.22340e-01  4.32260e-01]
 [-4.64971e+00  6.52580e-01  7.53550e-01]
 [-4.64986e+00  5.14670e-01  8.85150e-01]
 [-4.64996e+00  1.60750e-01  9.94500e-01]
 [-4.99990e+00  1.01254e+00  9.45300e-02]
 [-4.99924e+00  8.70270e-01  3.47380e-01]
 [-4.99932e+00  8.02310e-01  4.16130e-01]
 [-4.99976e+00  4.91150e-01  8.05210e-01]
 [-4.99995e+00  1.60720e-01  9.80690e-01]
 [-5.29975e+00  1.47910e-01  8.11040e-01]
 [-5.34912e+00  8.14180e-01  2.47110e-01]
 [-5.34880e+00  9.38380e-01 -3.01800e-02]
 [-6.49998e+00  6.76000e-01 -4.33500e-01]
 [-6.49993e+00  6.93960e-01 -7.48530e-01]
 [-6.49998e+00  6.10000e-01 -1.64800e-01]
 [-6.49998e+00  5.23000e-01 -4.88000e-02]
 [-6.49998e+00  2.40000e-01  1.09600e-01]
 [ 1.20924e+00  1.08002e+00 -1.32162e+00]
 [-5.56803e+00  1.19200e-01  5.68690e-01]
 [-5.29975e+00 -1.47910e-01  8.11040e-01]
 [-4.99995e+00 -1.60720e-01  9.80690e-01]
 [-4.64996e+00 -1.60750e-01  9.94500e-01]
 [ 1.20879e+00 -1.30180e-01  9.96070e-01]
 [ 1.20879e+00  1.30180e-01  9.96070e-01]
 [ 3.09302e+00 -4.08000e-02  1.27630e+00]
 [ 5.94202e+00  1.20200e-02  4.15720e+00]
 [ 7.04371e+00  0.00000e+00  4.15720e+00]
 [ 4.99823e+00 -1.30900e-01  1.19310e+00]
 [ 5.17128e+00 -1.31038e+00 -1.05594e+00]
 [ 6.13032e+00  1.10002e+00 -1.10694e+00]
 [ 2.98325e+00 -1.08002e+00 -1.35165e+00]
 [ 2.98325e+00  1.08002e+00 -1.35165e+00]
 [-6.49993e+00 -6.93960e-01 -7.48530e-01]
 [-4.99990e+00 -1.00002e+00 -9.43980e-01]
 [ 1.69220e-01 -1.99004e+00 -1.06328e+00]
 [ 5.00030e+00 -1.51003e+00  7.50090e-01]
 [ 5.00030e+00 -8.74020e-01  1.39912e+00]
 [ 5.00030e+00 -1.14902e+00  1.26010e+00]
 [ 5.00030e+00  8.74020e-01  1.39912e+00]
 [-7.07498e+00 -3.04060e-01 -2.64430e-01]
 [-7.07498e+00  1.39530e-01 -1.69390e-01]
 [-7.07498e+00  3.04060e-01 -2.64430e-01]
 [-7.07496e+00  4.03450e-01 -6.84270e-01]
 [-7.07498e+00  3.93010e-01 -4.95250e-01]
 [-7.07498e+00  3.54640e-01 -3.34030e-01]
 [-7.07498e+00  5.74500e-02 -1.55080e-01]
 [-7.07498e+00 -3.54640e-01 -3.34030e-01]
 [-7.07498e+00 -3.93010e-01 -4.95250e-01]
 [-7.07496e+00 -4.03450e-01 -6.84270e-01]
 [-7.07498e+00 -1.39530e-01 -1.69390e-01]
 [-7.07498e+00 -5.74500e-02 -1.55080e-01]
 [ 5.25718e+00 -2.44260e-01 -4.48880e-01]
 [ 5.27536e+00 -3.89800e-01 -4.46330e-01]
 [ 5.53408e+00 -2.55530e-01 -4.10060e-01]
 [ 5.85872e+00 -1.71970e-01 -3.64550e-01]
 [ 6.24669e+00 -1.27420e-01 -3.10160e-01]
 [ 6.24581e+00 -2.09800e-01 -3.10280e-01]
 [ 5.95749e+00 -2.42910e-01 -3.50700e-01]
 [ 5.68480e+00 -3.67020e-01 -3.88930e-01]
 [ 5.03026e+00 -3.10420e-01 -3.93900e-02]
 [ 5.21889e+00 -4.03500e-01 -1.75730e-01]
 [ 5.25457e+00 -4.76270e-01 -2.98000e-01]
 [ 5.49715e+00 -4.09140e-01 -1.46570e-01]
 [ 5.81174e+00 -3.67360e-01 -2.94000e-02]
 [ 6.19435e+00 -3.45080e-01  6.31900e-02]
 [ 6.20338e+00 -3.86270e-01 -7.58000e-03]
 [ 5.91904e+00 -4.02820e-01 -7.63900e-02]
 [ 5.66126e+00 -4.64880e-01 -2.21070e-01]
 [ 5.03026e+00 -8.15060e-01 -3.93800e-02]
 [ 5.21889e+00 -7.21990e-01 -1.75720e-01]
 [ 5.25457e+00 -6.49220e-01 -2.97990e-01]
 [ 5.49715e+00 -7.16350e-01 -1.46570e-01]
 [ 5.81174e+00 -7.58130e-01 -2.93900e-02]
 [ 6.19435e+00 -7.80400e-01  6.32000e-02]
 [ 6.20338e+00 -7.39220e-01 -7.57000e-03]
 [ 5.91904e+00 -7.22660e-01 -7.63900e-02]
 [ 5.66126e+00 -6.60610e-01 -2.21060e-01]
 [ 5.53366e+00 -5.62750e-01 -4.10120e-01]
 [ 5.25718e+00 -8.81240e-01 -4.48860e-01]
 [ 5.27536e+00 -7.35710e-01 -4.46320e-01]
 [ 5.53408e+00 -8.69980e-01 -4.10040e-01]
 [ 5.85872e+00 -9.53530e-01 -3.64530e-01]
 [ 6.24668e+00 -9.98080e-01 -3.10140e-01]
 [ 6.24581e+00 -9.15700e-01 -3.10270e-01]
 [ 5.95749e+00 -8.82600e-01 -3.50690e-01]
 [ 5.68480e+00 -7.58480e-01 -3.88920e-01]
 [ 5.15160e+00 -8.15100e-01 -9.04960e-01]
 [ 5.29547e+00 -7.22020e-01 -7.22020e-01]
 [ 5.29615e+00 -6.49240e-01 -5.94650e-01]
 [ 5.57102e+00 -7.16380e-01 -6.73530e-01]
 [ 5.90570e+00 -7.58170e-01 -6.99680e-01]
 [ 6.29903e+00 -7.80440e-01 -6.83500e-01]
 [ 6.28825e+00 -7.39250e-01 -6.12980e-01]
 [ 5.99595e+00 -7.22690e-01 -6.25000e-01]
 [ 5.70833e+00 -6.60630e-01 -5.56790e-01]
 [ 5.29547e+00 -4.03530e-01 -7.22040e-01]
 [ 5.29615e+00 -4.76290e-01 -5.94670e-01]
 [ 5.57102e+00 -4.09160e-01 -6.73560e-01]
 [ 5.90571e+00 -3.67390e-01 -6.99710e-01]
 [ 6.29903e+00 -3.45120e-01 -6.83530e-01]
 [ 6.28825e+00 -3.86300e-01 -6.13000e-01]
 [ 5.99595e+00 -4.02850e-01 -6.25020e-01]
 [ 5.70833e+00 -4.64900e-01 -5.56800e-01]
 [ 5.21889e+00  4.03500e-01 -1.75730e-01]
 [ 5.25718e+00  2.44260e-01 -4.48880e-01]
 [ 5.25457e+00  4.76270e-01 -2.98000e-01]
 [ 5.27536e+00  3.89800e-01 -4.46330e-01]
 [ 5.49715e+00  4.09140e-01 -1.46570e-01]
 [ 5.53408e+00  2.55530e-01 -4.10060e-01]
 [ 5.81174e+00  3.67360e-01 -2.94000e-02]
 [ 5.85872e+00  1.71970e-01 -3.64550e-01]
 [ 6.19435e+00  3.45080e-01  6.31900e-02]
 [ 6.24669e+00  1.27420e-01 -3.10160e-01]
 [ 6.20338e+00  3.86270e-01 -7.58000e-03]
 [ 6.24581e+00  2.09800e-01 -3.10280e-01]
 [ 5.91904e+00  4.02820e-01 -7.63900e-02]
 [ 5.95749e+00  2.42910e-01 -3.50700e-01]
 [ 5.66126e+00  4.64880e-01 -2.21070e-01]
 [ 5.68480e+00  3.67020e-01 -3.88930e-01]
 [ 5.21889e+00  7.21990e-01 -1.75720e-01]
 [ 5.25457e+00  6.49220e-01 -2.97990e-01]
 [ 5.49715e+00  7.16350e-01 -1.46570e-01]
 [ 5.81174e+00  7.58130e-01 -2.93900e-02]
 [ 6.19435e+00  7.80400e-01  6.32000e-02]
 [ 6.20338e+00  7.39220e-01 -7.57000e-03]
 [ 5.91904e+00  7.22660e-01 -7.63900e-02]
 [ 5.66126e+00  6.60610e-01 -2.21060e-01]
 [ 5.25718e+00  8.81240e-01 -4.48860e-01]
 [ 5.27536e+00  7.35710e-01 -4.46320e-01]
 [ 5.53408e+00  8.69980e-01 -4.10040e-01]
 [ 5.85872e+00  9.53530e-01 -3.64530e-01]
 [ 6.24668e+00  9.98080e-01 -3.10140e-01]
 [ 6.24581e+00  9.15700e-01 -3.10270e-01]
 [ 5.95749e+00  8.82600e-01 -3.50690e-01]
 [ 5.68480e+00  7.58480e-01 -3.88920e-01]
 [ 5.53366e+00  5.62750e-01 -4.10120e-01]
 [ 5.29547e+00  7.22020e-01 -7.22020e-01]
 [ 5.29615e+00  6.49240e-01 -5.94650e-01]
 [ 5.57102e+00  7.16380e-01 -6.73530e-01]
 [ 5.90570e+00  7.58170e-01 -6.99680e-01]
 [ 6.29903e+00  7.80440e-01 -6.83500e-01]
 [ 6.28825e+00  7.39250e-01 -6.12980e-01]
 [ 5.99595e+00  7.22690e-01 -6.25000e-01]
 [ 5.70833e+00  6.60630e-01 -5.56790e-01]
 [ 5.29547e+00  4.03530e-01 -7.22040e-01]
 [ 5.29615e+00  4.76290e-01 -5.94670e-01]
 [ 5.57102e+00  4.09160e-01 -6.73560e-01]
 [ 5.90571e+00  3.67390e-01 -6.99710e-01]
 [ 6.29903e+00  3.45120e-01 -6.83530e-01]
 [ 6.28825e+00  3.86300e-01 -6.13000e-01]
 [ 5.99595e+00  4.02850e-01 -6.25020e-01]
 [ 5.70833e+00  4.64900e-01 -5.56800e-01]
 [ 5.16564e+00 -3.18490e-01  6.37330e-01]
 [ 5.16610e+00 -1.59250e-01  9.13150e-01]
 [ 4.99850e+00 -2.52330e-01  1.07464e+00]
 [ 5.18400e+00 -1.72950e-01  6.37300e-01]
 [ 5.18425e+00 -8.64800e-02  7.87080e-01]
 [ 5.44525e+00 -3.07220e-01  6.36860e-01]
 [ 5.44570e+00 -1.53620e-01  9.02920e-01]
 [ 5.77307e+00 -3.90780e-01  6.36310e-01]
 [ 5.77363e+00 -1.95390e-01  9.74730e-01]
 [ 6.16482e+00 -4.35330e-01  6.35650e-01]
 [ 6.16545e+00 -2.17670e-01  1.01265e+00]
 [ 6.16394e+00 -3.52950e-01  6.35650e-01]
 [ 6.16445e+00 -1.76480e-01  9.41310e-01]
 [ 5.87280e+00 -3.19840e-01  6.36140e-01]
 [ 5.87326e+00 -1.59930e-01  9.13130e-01]
 [ 5.59744e+00 -1.95730e-01  6.36600e-01]
 [ 5.59772e+00 -9.78700e-02  8.06110e-01]
 [ 5.44482e+00  0.00000e+00  6.36860e-01]
 [ 5.16610e+00  1.59240e-01  9.13160e-01]
 [ 5.18425e+00  8.64700e-02  7.87080e-01]
 [ 5.44570e+00  1.53600e-01  9.02930e-01]
 [ 5.77363e+00  1.95380e-01  9.74740e-01]
 [ 6.16545e+00  2.17650e-01  1.01267e+00]
 [ 6.16445e+00  1.76460e-01  9.41320e-01]
 [ 5.87326e+00  1.59910e-01  9.13140e-01]
 [ 5.59772e+00  9.78600e-02  8.06110e-01]
 [ 5.16564e+00  3.18490e-01  6.37350e-01]
 [ 4.99777e+00  5.04640e-01  6.37640e-01]
 [ 5.18400e+00  1.72950e-01  6.37310e-01]
 [ 5.44525e+00  3.07220e-01  6.36870e-01]
 [ 5.77307e+00  3.90780e-01  6.36330e-01]
 [ 6.16482e+00  4.35330e-01  6.35680e-01]
 [ 6.16394e+00  3.52950e-01  6.35670e-01]
 [ 5.87280e+00  3.19840e-01  6.36160e-01]
 [ 5.59744e+00  1.95730e-01  6.36610e-01]
 [ 5.16518e+00  1.59260e-01  3.61520e-01]
 [ 4.99703e+00  2.52350e-01  2.00600e-01]
 [ 5.18375e+00  8.64900e-02  4.87520e-01]
 [ 5.44481e+00  1.53630e-01  3.70810e-01]
 [ 5.77250e+00  1.95410e-01  2.97900e-01]
 [ 6.16419e+00  2.17690e-01  2.58660e-01]
 [ 6.16342e+00  1.76500e-01  3.30000e-01]
 [ 5.87233e+00  1.59940e-01  3.59160e-01]
 [ 5.59715e+00  9.78800e-02  4.67110e-01]
 [ 5.16518e+00 -1.59220e-01  3.61490e-01]
 [ 4.99703e+00 -2.52280e-01  2.00560e-01]
 [ 5.18375e+00 -8.64600e-02  4.87510e-01]
 [ 5.44481e+00 -1.53590e-01  3.70780e-01]
 [ 5.77250e+00 -1.95360e-01  2.97870e-01]
 [ 6.16419e+00 -2.17630e-01  2.58630e-01]
 [ 6.16342e+00 -1.76450e-01  3.29980e-01]
 [ 5.87233e+00 -1.59900e-01  3.59140e-01]
 [ 5.59715e+00 -9.78500e-02  4.67090e-01]
 [ 5.09093e+00 -1.06739e+00 -4.72160e-01]
 [ 5.17128e+00  1.31038e+00 -1.05594e+00]
 [ 5.15161e+00  3.10470e-01 -9.05000e-01]
 [ 5.15161e+00 -3.10470e-01 -9.05000e-01]
 [ 5.03026e+00  8.15060e-01 -3.93800e-02]
 [ 5.03026e+00  3.10420e-01 -3.93900e-02]
 [ 5.09093e+00 -5.81100e-02 -4.72180e-01]
 [ 5.09093e+00  5.81100e-02 -4.72180e-01]
 [ 5.00030e+00 -1.21000e+00  1.73070e-01]
 [ 5.00030e+00  1.21000e+00  1.73070e-01]
 [ 5.00030e+00 -1.42803e+00  4.42100e-01]
 [ 4.99776e+00 -5.04640e-01  6.37610e-01]
 [ 4.99850e+00  2.52300e-01  1.07465e+00]
 [ 4.99823e+00  1.30900e-01  1.19310e+00]
 [ 5.00030e+00  1.51003e+00  7.50090e-01]
 [ 5.15160e+00  8.15100e-01 -9.04960e-01]
 [ 5.09093e+00  1.06739e+00 -4.72160e-01]
 [ 3.07022e+00 -1.05363e+00  4.49900e-01]
 [-5.34921e+00  7.37230e-01  3.23970e-01]
 [-5.34921e+00 -7.37230e-01  3.23970e-01]
 [-5.34948e+00 -4.70930e-01  5.66060e-01]
 [-6.49998e+00 -9.88300e-02  1.33440e-01]
 [-6.49998e+00  9.88300e-02  1.33440e-01]
 [-6.49998e+00 -5.23000e-01 -4.88000e-02]
 [-5.34948e+00  4.70930e-01  5.66060e-01]
 [-4.99990e+00  1.00002e+00 -9.43980e-01]
 [ 8.40210e-01  2.48005e+00 -1.05031e+00]
 [ 1.20924e+00 -1.08002e+00 -6.36410e-01]
 [ 3.80426e+00  4.68210e+00 -9.38960e-01]
 [ 5.00030e+00 -1.30293e+00 -1.25995e+00]
 [ 3.80426e+00 -4.68210e+00 -9.38960e-01]
 [-4.64986e+00 -5.14670e-01  8.85150e-01]
 [-4.99949e+00  6.81710e-01  5.69240e-01]
 [-4.64942e+00  8.60390e-01  4.97000e-01]
 [-4.90671e+00  6.20190e-01  6.86500e-01]
 [-4.64942e+00 -8.60390e-01  4.97000e-01]
 [-4.99949e+00 -6.81710e-01  5.69240e-01]]
Answer seems to be incorrect

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-7-007195bf1817> in <module>
      1 from answercheck import checkanswer
----> 2 checkanswer.matrix(vertices, '25bcaa0c8991d0d80b7d8ec89baa38c3')

~/_CMSE314_F20/CMSE314/answercheck.py in matrix(A, hashtag, decimal_accuracy)
    150         """Function to check matrix type before hashing."""
    151         A = checkanswer.make_matrix(A, decimal_accuracy)
--> 152         return checkanswer.basic(A, hashtag)
    153 
    154     # TODO: Not complete or tested.

~/_CMSE314_F20/CMSE314/answercheck.py in basic(var, hashtag)
     48             else:
     49                 print("Answer seems to be incorrect\n")
---> 50                 assert checktag == hashtag, f"Answer is incorrect {checktag}"
     51         else:
     52             raise TypeError(f"No answer hastag provided: {checktag}")

AssertionError: Answer is incorrect a3f239680626185132a41542951e5694
from answercheck import checkanswer
checkanswer(faces,'33a415ce4e4ce818822df4f8c97f60b3')
Testing [[309, 31, 293], [75, 307, 305], [293, 87, 32], [309, 30, 31], [87, 293, 31], [86, 32, 87, 77], [86, 77, 297], [297, 75, 305], [297, 77, 75], [94, 2, 95, 3], [3, 286, 42, 94], [93, 1, 2, 42], [2, 1, 92, 95], [40, 0, 92, 41], [40, 41, 286], [42, 2, 94], [286, 41, 93, 42], [41, 92, 1, 93], [95, 92, 0], [274, 97, 53], [95, 222, 285, 286], [96, 276, 154], [275, 280, 279, 276], [275, 274, 288], [282, 281, 127, 278], [282, 289, 274], [256, 50, 247], [281, 302, 96], [95, 5, 105], [302, 11, 96], [103, 284, 222], [96, 154, 273], [283, 281, 265], [285, 287, 286], [136, 127, 281], [282, 278, 277], [247, 287, 285], [5, 104, 105], [274, 53, 282], [283, 265, 284], [95, 286, 3], [283, 284, 103], [247, 50, 287], [282, 277, 289], [273, 136, 281], [288, 274, 289], [96, 11, 97, 274], [47, 106, 44], [95, 105, 103], [281, 282, 256, 265], [96, 274, 275, 276], [103, 222, 95], [256, 282, 50], [96, 273, 281], [127, 279, 280, 278], [286, 287, 47], [286, 47, 44], [308, 30, 309], [293, 32, 294], [107, 117, 38], [79, 78, 73, 72], [48, 46, 47], [4, 0, 90, 23], [9, 290, 19, 18], [293, 294, 37], [77, 76, 75], [80, 81, 110, 111], [64, 65, 45, 46], [29, 308, 309], [4, 104, 5], [29, 28, 25, 308], [67, 61, 58, 298], [77, 87, 88, 76], [117, 37, 294, 118], [82, 80, 111, 112], [63, 64, 46, 48], [34, 36, 35], [22, 7, 6], [23, 90, 89, 304], [61, 51, 52, 58], [295, 84, 108, 113], [78, 291, 74, 73], [49, 48, 287], [21, 22, 26], [281, 9, 10, 302], [292, 293, 296], [70, 71, 91, 66], [111, 38, 112], [309, 293, 292], [304, 89, 88], [307, 69, 306], [295, 86, 297], [113, 38, 118], [70, 76, 71], [44, 106, 43], [7, 22, 21], [6, 4, 23, 22], [286, 43, 40], [306, 68, 73, 74], [91, 90, 0, 40], [62, 61, 67], [27, 28, 33, 34], [104, 6, 7, 105], [31, 88, 87], [48, 47, 287], [81, 80, 298], [114, 36, 296, 107], [112, 38, 109], [72, 73, 68, 67], [28, 29, 292, 33], [290, 103, 8], [21, 26, 308], [53, 52, 51, 282], [82, 78, 79], [82, 79, 80], [47, 46, 45, 106], [24, 19, 20, 25], [300, 10, 9, 18], [38, 114, 107], [305, 306, 74], [109, 38, 108], [291, 297, 305], [305, 307, 306], [69, 65, 64], [293, 37, 296], [4, 5, 95], [84, 83, 109, 108], [61, 62, 49, 51], [101, 24, 27], [8, 105, 7], [309, 292, 29], [69, 70, 65], [76, 88, 89, 71], [65, 70, 66], [296, 36, 33, 292], [105, 8, 103], [24, 18, 19], [43, 106, 45], [84, 295, 297], [116, 100, 35, 115], [110, 38, 111], [306, 69, 64], [34, 33, 36], [22, 304, 26], [101, 300, 18, 24], [49, 287, 50], [79, 72, 298], [83, 297, 291], [48, 49, 62, 63], [31, 304, 88], [0, 4, 95], [31, 30, 26, 304], [65, 66, 43, 45], [295, 294, 32, 86], [290, 9, 281], [80, 79, 298], [308, 26, 30], [83, 84, 297], [115, 35, 36, 114], [291, 78, 82, 83], [282, 51, 50], [308, 25, 20, 21], [283, 290, 281], [101, 35, 100], [64, 63, 68, 306], [294, 295, 113, 118], [72, 67, 298], [38, 115, 114], [104, 4, 6], [22, 23, 304], [38, 116, 115], [76, 70, 75], [108, 38, 113], [296, 37, 117, 107], [74, 291, 305], [38, 117, 118], [20, 19, 290, 8], [8, 7, 21, 20], [286, 44, 43], [70, 69, 307, 75], [83, 82, 112, 109], [66, 91, 40, 43], [24, 25, 28, 27], [103, 290, 283], [101, 27, 34], [68, 63, 62, 67], [71, 89, 90, 91], [51, 49, 50], [101, 34, 35], [15, 14, 16], [303, 14, 15], [299, 56, 59], [13, 12, 303], [58, 52, 54, 56], [59, 56, 57], [17, 300, 102], [299, 58, 56], [303, 12, 14], [55, 54, 52, 53], [14, 12, 10, 300], [60, 58, 299], [56, 54, 301], [102, 300, 101], [16, 14, 300], [302, 10, 12, 13], [57, 56, 301], [301, 54, 55], [16, 300, 17], [298, 58, 60], [301, 55, 53], [17, 102, 39], [15, 16, 98], [85, 60, 299], [98, 303, 15], [302, 13, 303], [98, 302, 303], [16, 17, 98], [301, 53, 99], [57, 301, 99], [99, 85, 299], [17, 39, 98], [99, 59, 57], [99, 299, 59], [100, 116, 110, 81], [101, 100, 81, 298], [116, 38, 110], [98, 99, 53, 302], [302, 53, 97, 11], [85, 99, 98, 39], [39, 102, 60, 85], [298, 60, 102, 101], [237, 254, 245], [193, 201, 200, 192], [152, 161, 162, 153], [143, 152, 153, 144], [183, 193, 192, 181], [237, 245, 236], [271, 233, 231, 270], [235, 236, 234, 233], [203, 194, 185], [133, 142, 143, 134], [142, 151, 152, 143], [203, 202, 194], [236, 245, 244, 234], [272, 235, 233, 271], [237, 236, 235], [184, 183, 181, 182], [134, 143, 144, 135], [153, 162, 145], [194, 202, 201, 193], [234, 244, 243, 232], [263, 272, 271, 262], [218, 184, 182, 217], [186, 185, 183, 184], [135, 144, 145], [160, 168, 169, 161], [203, 219, 211], [254, 263, 262, 253], [233, 234, 232, 231], [185, 194, 193, 183], [144, 153, 145], [151, 160, 161, 152], [203, 211, 202], [245, 254, 253, 244], [237, 235, 272], [203, 186, 219], [168, 124, 125, 169], [125, 134, 135, 126], [162, 170, 145], [202, 211, 210, 201], [244, 253, 252, 243], [237, 272, 263], [210, 218, 217, 209], [169, 125, 126, 170], [126, 135, 145], [161, 169, 170, 162], [201, 210, 209, 200], [237, 263, 254], [253, 262, 261, 252], [211, 219, 218, 210], [170, 126, 145], [124, 133, 134, 125], [203, 185, 186], [219, 186, 184, 218], [262, 271, 270, 261], [250, 259, 258, 249], [208, 216, 215, 207], [156, 164, 165, 157], [131, 140, 141, 132], [178, 177, 175, 176], [214, 176, 174, 213], [269, 229, 227, 268], [226, 240, 239, 224], [190, 198, 197, 189], [149, 158, 159, 150], [130, 139, 140, 131], [176, 175, 173, 174], [229, 230, 228, 227], [268, 227, 225, 267], [228, 241, 240, 226], [191, 199, 198, 190], [138, 147, 148, 139], [129, 138, 139, 130], [179, 191, 190, 177], [227, 228, 226, 225], [267, 225, 223, 266], [230, 242, 241, 228], [175, 189, 188, 173], [139, 148, 149, 140], [148, 157, 158, 149], [189, 197, 196, 188], [242, 251, 250, 241], [258, 267, 266, 257], [215, 178, 176, 214], [180, 179, 177, 178], [120, 129, 130, 121], [166, 122, 123, 167], [207, 215, 214, 206], [249, 258, 257, 248], [251, 260, 259, 250], [197, 206, 205, 196], [157, 165, 166, 158], [122, 131, 132, 123], [165, 121, 122, 166], [206, 214, 213, 205], [260, 269, 268, 259], [240, 249, 248, 239], [198, 207, 206, 197], [158, 166, 167, 159], [121, 130, 131, 122], [164, 120, 121, 165], [216, 180, 178, 215], [259, 268, 267, 258], [241, 250, 249, 240], [199, 208, 207, 198], [147, 156, 157, 148], [140, 149, 150, 141], [177, 190, 189, 175], [225, 226, 224, 223], [224, 239, 238, 221], [163, 119, 120, 164], [127, 136, 137, 128], [195, 204, 288, 289], [264, 220, 284, 265], [205, 213, 212, 204], [137, 146, 147, 138], [173, 188, 187, 171], [248, 257, 255, 246], [220, 221, 222, 284], [154, 276, 163, 155], [273, 154, 155, 146], [212, 172, 280, 275], [257, 266, 264, 255], [188, 196, 195, 187], [119, 128, 129, 120], [172, 171, 278, 280], [238, 246, 247, 285], [204, 212, 275, 288], [136, 273, 146, 137], [155, 163, 164, 156], [223, 224, 221, 220], [246, 255, 256, 247], [171, 187, 277, 278], [279, 127, 128, 119], [187, 195, 289, 277], [255, 264, 265, 256], [213, 174, 172, 212], [146, 155, 156, 147], [174, 173, 171, 172], [239, 248, 246, 238], [221, 238, 285, 222], [276, 279, 119, 163], [128, 137, 138, 129], [196, 205, 204, 195], [266, 223, 220, 264], [232, 243, 242, 230], [123, 132, 133, 124], [261, 270, 269, 260], [141, 150, 151, 142], [252, 261, 260, 251], [150, 159, 160, 151], [243, 252, 251, 242], [159, 167, 168, 160], [200, 209, 208, 199], [270, 231, 229, 269], [132, 141, 142, 133], [231, 232, 230, 229], [182, 181, 179, 180], [217, 182, 180, 216], [181, 192, 191, 179], [209, 217, 216, 208], [192, 200, 199, 191], [167, 123, 124, 168]]
Answer seems to be incorrect

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-8-b8bc620f71b1> in <module>
      1 from answercheck import checkanswer
----> 2 checkanswer(faces,'33a415ce4e4ce818822df4f8c97f60b3')

~/_CMSE314_F20/CMSE314/answercheck.py in __init__(self, var, hashtag)
     23 
     24     def __init__(self, var, hashtag=None):
---> 25         checkanswer.basic(var, hashtag)
     26 
     27     def basic(var, hashtag=None):

~/_CMSE314_F20/CMSE314/answercheck.py in basic(var, hashtag)
     48             else:
     49                 print("Answer seems to be incorrect\n")
---> 50                 assert checktag == hashtag, f"Answer is incorrect {checktag}"
     51         else:
     52             raise TypeError(f"No answer hastag provided: {checktag}")

AssertionError: Answer is incorrect 935a6bc32b7cd586c03d5150e2340156

Now lets apply a few simple affine transforms as matrix multiplications in the following form:

$$P_2 = MP$$

Where $M$ is the transformation matrix, $P$ are the 3D points before the transformation and $P_2$ are the resulting points. Remember from class that all 3D transfroms can be represented as a $4 \times 4$ matrix of the following form:

$$ M = \left[ \begin{matrix} R_{11} & R_{12} & R_{13} & T_x \\ R_{21} & R_{22} & R_{23} & T_y \\ R_{31} & R_{32} & R_{33} & T_z \\ 0 & 0 & 0 & 1 \end{matrix} \right] $$

Where the $3x3$ submatrix $R$ is affine part and $T$ is the translation vector. The bottom row is always zeros and a 1 just to make the math work out. In order to use this $4 \times 4$ matrix we need to put our points in a $4 \times n$ matrix where the first row is the $x$ coordinate, the second row is the $y$ coordinate, the third row is the $z$ coordinate and the fourth row are just ones; as follows: $$ P = \left[ \begin{matrix} p_{x1} & p_{x2} & p_{x3} &\dots & p_{xn} \\ p_{y1} & p_{y2} & p_{y3} &\dots & p_{yn} \\ p_{z1} & p_{z2} & p_{z3} &\dots & p_{zn} \\ 1 & 1 & 1 & \dots & 1 \end{matrix} \right] $$

**Do This:** (10 pts) Create a ($4 \times n$) point matrix $P$ from the teapot vertices.

# Put your answer to the above question here. 
from answercheck import checkanswer
checkanswer.matrix(P,'96770f757e8013453560d4b58bd623e1')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-10-caf6c5a777f8> in <module>
      1 from answercheck import checkanswer
----> 2 checkanswer.matrix(P,'96770f757e8013453560d4b58bd623e1')

NameError: name 'P' is not defined

The following will plot the x and y rows in $P$ on the xy-axis:

plt.scatter(np.array(P[0,:]),np.array(P[1,:]));
plt.axis('equal');
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-ce0290b43b67> in <module>
----> 1 plt.scatter(np.array(P[0,:]),np.array(P[1,:]));
      2 plt.axis('equal');

NameError: name 'P' is not defined

Now lets apply a simple ($4 \times 4$) transformation T that translate the teapot by 50 units in the y direction and plots the teapot.

$$P_2 = TP$$
T = np.matrix([[1, 0, 0, 0], 
             [0, 1, 0, 50],
             [0, 0, 1, 0],
             [0,0,0,1]])

P2 = T*P

#NOTE: to get the plotting to work we convert the Matrices to np.arrays
plt.scatter(np.array(P2[0,:]),np.array(P2[1,:]));
plt.axis('equal');
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-12-e2cb25e933a7> in <module>
      4              [0,0,0,1]])
      5 
----> 6 P2 = T*P
      7 
      8 #NOTE: to get the plotting to work we convert the Matrices to np.arrays

NameError: name 'P' is not defined

**Question:** (10 pts) Construct 3D affine transform using a matrix called R to rotate the coordinate system down by 60 degrees around the z-axis. Apply the transform to the original teapot points (P) and plot the rotated points (P2) in the xy-plane (as above). It should look like the pot is tilted in a direction to poor the tea out of the pot.

Hint: many implementations for sin and cos assume the imput is in Radians instead of Degrees, you may need to make a conversion.

#Put your answer to the above question here
from answercheck import checkanswer
checkanswer.matrix(R,'f971b9c9876afc881d2fb2b361cc6761')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-14-f8aec63a540b> in <module>
      1 from answercheck import checkanswer
----> 2 checkanswer.matrix(R,'f971b9c9876afc881d2fb2b361cc6761')

NameError: name 'R' is not defined

**Question:** (10 pts) Construct another transform S that scales the x and z axes by a factor of 2 while leaving the y axes the same. Apply the transform to the original teapot points (P) and plot the results (P2) in the xy-plane (as above). It should look like a flatter teapot.

#Put your answer to the above question here
from answercheck import checkanswer
checkanswer.matrix(S,'98688524afa007f8042263e3d9f9ffc6')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-16-bd24b9b129ea> in <module>
      1 from answercheck import checkanswer
----> 2 checkanswer.matrix(S,'98688524afa007f8042263e3d9f9ffc6')

NameError: name 'S' is not defined

**Question**: (10 pts) Create a fourth affine transform called G that is a combination of the previous transforms. First skew the original points (P) with S and then rotate the results by R and translate the by T. Plot the results (P2). Picture should look like a flat rotated teapot that is picked up and poring out.

#Put your answer to the above question here
from answercheck import checkanswer
checkanswer.matrix(G,'9fb98fe93d326a6b7da6526ccd227533')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-18-63a820fff30c> in <module>
      1 from answercheck import checkanswer
----> 2 checkanswer.matrix(G,'9fb98fe93d326a6b7da6526ccd227533')

NameError: name 'G' is not defined

Just for fun, we can use the following code to try and plot our new rotated teapot in "3D". Note again that this function isn't that great since it scales the axis weirdly.

plotobjdata(np.array(P2[0:3]).T, faces)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-19-1b82a1a99903> in <module>
----> 1 plotobjdata(np.array(P2[0:3]).T, faces)

NameError: name 'P2' is not defined

**Question**: (10 pts) The affine transforms we used are all invertible. Calculate the inverse of G and apply it to the P2 points from the previous question and plot the results (P3).

# YOUR CODE HERE
raise NotImplementedError()
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-20-15b94d1fa268> in <module>
      1 # YOUR CODE HERE
----> 2 raise NotImplementedError()

NotImplementedError: 

**Question**: (5 pts) Assuming the above calculations are correct the results from the previous question (P3) should be exactly the same as the original points P. However, the following code does not produce only zeros. Explain why?

P3-P
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-21-03a818acacb3> in <module>
----> 1 P3-P

NameError: name 'P3' is not defined

YOUR ANSWER HERE


3. Animations

Lets say we want to create an animation of the teapot as it is rotating the full 60 degrees. To get this to work we need to create a "flip-book" effect. Rotate the teapot a little - show the results - rotate the teapot a little more - show the results - until we hit our 60 degree target.

The following function can be used to "animate" figures inside of jupyter notebooks:

%matplotlib inline
import matplotlib.pylab as plt
from IPython.display import display, clear_output
import time

imageindex=0

def show_animation(delay=0.01):
    global imageindex
    fig = plt.gcf()
    #fig.savefig(f"./images/image_{imageindex:03d}.jpg")
    #imageindex+=1
    time.sleep(delay)       # Sleep for half a second to slow down the animation
    clear_output(wait=True) # Clear output for dynamic display
    display(fig)            # Reset display
    fig.clear()             # Prevent overlapping and layered plots

We can use the above function to create an animation. This one applies a simple translation at each step:

Pa = P
T = np.matrix([[1, 0, 0, 15], 
             [0, 1, 0, 5],
             [0, 0, 1, 0],
             [0,0,0,1]])

for i in range(20):
    Pa = T*Pa
    plt.scatter(np.array(Pa[0,:]),np.array(Pa[1,:]));
    plt.axis('equal')
    plt.axis('off')
    plt.axis([-150,150,-150,150])
    show_animation(delay=0.01)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-23-a1eb33f221f0> in <module>
----> 1 Pa = P
      2 T = np.matrix([[1, 0, 0, 15], 
      3              [0, 1, 0, 5],
      4              [0, 0, 1, 0],
      5              [0,0,0,1]])

NameError: name 'P' is not defined

**DO THIS**: (15 pts) Modify the above code to rotate instead of translate. The final pot should be at a 60 degree angle (like we did above) but this time you wnat to make about 20 steps between zero rotation and 60 so that the animation looks smooth. (HINT: you are trying to recreate the animation shown at the top of this assignment).

# YOUR CODE HERE
raise NotImplementedError()
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-24-15b94d1fa268> in <module>
      1 # YOUR CODE HERE
----> 2 raise NotImplementedError()

NotImplementedError: 

4. Make your own Movie

**Do This**: (20 pts) Using the objects from make your own "flip-book" video. Experiment and be creative. Try including more than one type of transformation, multiple transforms at the same time, more than one 3D object etc. Be creative and show us you what you can do:

# YOUR CODE HERE
raise NotImplementedError()
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-25-15b94d1fa268> in <module>
      1 # YOUR CODE HERE
----> 2 raise NotImplementedError()

NotImplementedError: 

**Question**: In your own words, describe what the above animation is doing. (sometimes it can be hard for instructors to tell what is going on so this description will help us evaluate your animation).

Put your description here.


Congratulations, we're done!

Turn in your assignment using D2L no later than 11:59pm on the day of class. See links at the end of this document for access to the class timeline for your section.

Written by Dirk Colbry, Michigan State University Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.