"""
A matrix will be an N sized list of 4 element lists.
Each individual list will represent an [x, y, z, 1] point.
For multiplication purposes, consider the lists like so:
x0  x1      xn
y0  y1      yn
z0  z1  ... zn
1  1        1
"""
import math

def make_bezier():
    return [
        [-1, 3, -3, 1],
        [3, -6, 3, 0],
        [-3, 3, 0, 0],
        [1, 0, 0, 0]
    ]

def make_hermite():
    return [
        [2, -3, 0, 1],
        [-2, 3, 0, 0],
        [1, -2, 1, 0],
        [1, -1, 0, 0]
    ]

def generate_curve_coefs(p0, p1, p2, p3, t):
    coefs = [[p0, p1, p2, p3]]
    if t == 'hermite':
        curve = make_hermite()
    else:
        curve = make_bezier()

    matrix_mult(curve, coefs)
    return coefs

def make_translate(x, y, z):
    t = new_matrix()
    ident(t)
    t[3][0] = x
    t[3][1] = y
    t[3][2] = z
    return t

def make_scale(x, y, z):
    t = new_matrix()
    ident(t)
    t[0][0] = x
    t[1][1] = y
    t[2][2] = z
    return t

def make_rotX(theta):
    t = new_matrix()
    ident(t)
    t[1][1] = math.cos(theta)
    t[2][1] = -math.sin(theta)
    t[1][2] = math.sin(theta)
    t[2][2] = math.cos(theta)
    return t

def make_rotY(theta):
    t = new_matrix()
    ident(t)
    t[0][0] = math.cos(theta)
    t[0][2] = -math.sin(theta)
    t[2][0] = math.sin(theta)
    t[2][2] = math.cos(theta)
    return t

def make_rotZ(theta):
    t = new_matrix()
    ident(t)
    t[0][0] = math.cos(theta)
    t[1][0] = -math.sin(theta)
    t[0][1] = math.sin(theta)
    t[1][1] = math.cos(theta)
    return t

#print the matrix such that it looks like
#the template in the top comment
def print_matrix(matrix):
    s = ''
    for r in range(len(matrix[0])):
        for c in range(len(matrix)):
            s+= str(matrix[c][r]) + ' '
        s += '\n'
    print (s)

#turn the paramter matrix into an identity matrix
#you may assume matrix is square
def ident(matrix):
    for r in range(len(matrix[0])):
        for c in range(len(matrix)):
            if r == c:
                matrix[c][r] = 1
            else:
                matrix[c][r] = 0

#multiply m1 by m2, modifying m2 to be the product
#m1 * m2 -> m2
def matrix_mult(m1, m2):
    point = 0
    for row in m2:
        #get a copy of the next point
        tmp = row[:]

        for r in range(4):
            m2[point][r] = (m1[0][r] * tmp[0] +
                            m1[1][r] * tmp[1] +
                            m1[2][r] * tmp[2] +
                            m1[3][r] * tmp[3])
        point += 1

def new_matrix(rows = 4, cols = 4):
    m = []
    for c in range(cols):
        m.append([])
        for r in range(rows):
            m[c].append(0)
    return m

[((57, 14, 57, 29), 'math.cos', 'math.cos', ({(57, 23, 57, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((59, 14, 59, 29), 'math.sin', 'math.sin', ({(59, 23, 59, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((60, 14, 60, 29), 'math.cos', 'math.cos', ({(60, 23, 60, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((66, 14, 66, 29), 'math.cos', 'math.cos', ({(66, 23, 66, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((68, 14, 68, 29), 'math.sin', 'math.sin', ({(68, 23, 68, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((69, 14, 69, 29), 'math.cos', 'math.cos', ({(69, 23, 69, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((75, 14, 75, 29), 'math.cos', 'math.cos', ({(75, 23, 75, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((77, 14, 77, 29), 'math.sin', 'math.sin', ({(77, 23, 77, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((78, 14, 78, 29), 'math.cos', 'math.cos', ({(78, 23, 78, 28): 'theta'}, {}), '(theta)', False, 'import math\n'), ((58, 15, 58, 30), 'math.sin', 'math.sin', ({(58, 24, 58, 29): 'theta'}, {}), '(theta)', False, 'import math\n'), ((67, 15, 67, 30), 'math.sin', 'math.sin', ({(67, 24, 67, 29): 'theta'}, {}), '(theta)', False, 'import math\n'), ((76, 15, 76, 30), 'math.sin', 'math.sin', ({(76, 24, 76, 29): 'theta'}, {}), '(theta)', False, 'import math\n')]