'Python Matrix Multiplication receives Error "can't multiply sequence by non-int of type 'list'"

I want to print out

P_parallel = S_parallel_matrix * T_parallel_matrix * SH_xy * Rot_n_up_t * translation_matrix

When I run the code, I get the following error:

line 182, in perspective_projection
P_parallel = S_parallel_matrix * T_parallel_matrix
TypeError: can't multiply sequence by non-int of type 'list'

I tried to split my multiplication, so I first tried to multiply:

P_parallel = S_parallel_matrix * T_parallel_matrix

Then I directly got the same error again and it was highlighting the T_parallel_matrix. So I know that it is because of the T_parallel_matrix.

This is my main.py code:

from __future__ import print_function, division, unicode_literals, absolute_import
import numpy as np
from mat4x4 import Mat4x4
from vec3 import Vec3


# Function perspective_projection
def perspective_projection(P, up, normal, v, l, r, b, t, n, f):

# 4x4 Translation-Matrix T(-Px, -Py, -Pz)
translation_matrix = [[1, 0, 0, (-P.x)],
                      [0, 1, 0, (-P.y)],
                      [0, 0, 1, (-P.z)],
                      [0, 0, 0, 1]
                      ]
print('Translationsmatrix: ' + str(translation_matrix))
# return

# Conversion of viewing volume to standard orientation z' = n (normal of the image plane) 1x3 matrix
z_strich = normal
print('z_strich: ' + str(z_strich))
# return

# Calculation x' = up X z' / |up X z'|
x_strich = up.cross(z_strich) / abs(up.cross(z_strich))
print('x_strich: ' + str(x_strich))
# return

# Calculation y' = z' X x'
y_strich = z_strich.cross(x_strich)
print('y_strich: ' + str(y_strich))
# return

# 4x4 Rotationmatrix R(n, up)
Rot_n_up = [[x_strich.x, y_strich.x, z_strich.x, 0],
            [x_strich.y, y_strich.y, z_strich.y, 0],
            [x_strich.z, y_strich.z, z_strich.z, 0],
            [0, 0, 0, 1]
            ]
print('Rotationsmatrix R(n, up): ' + str(Rot_n_up))
# return

# Inverse Rotationmatrix R(n, up)-1 = R(n, up)T 
Rot_n_up_i = [[x_strich.x, x_strich.y, x_strich.z, 0],
              [y_strich.x, y_strich.y, y_strich.z, 0],
              [z_strich.x, z_strich.y, z_strich.z, 0],
              [0, 0, 0, 1]
              ]
print('Inverse Rotationmatrix R(n, up)-1: ' + str(Rot_n_up_i))
# return

# Inverse Rotationmatrix R(n, up)T = R(n, up)-1 
Rot_n_up_t = np.linalg.inv(Rot_n_up_i)
print('Inverse Rotationmatrix R(n, up)T: ' + str(Rot_n_up_t))

# Standard orientation: R(n, up)T * T(-Px, -Py, -Pz)
standard_orientation = Rot_n_up_t * translation_matrix
print('Standard orientation: ' + str(standard_orientation))
# return

# Transfer to the canonical visual volume
# SHxy = 4x4 Matrix -> SHxy * v = (0 0 vz) <- 1x3 Matrix
sh_x = -(v.x / v.z)
sh_y = -(v.y / v.z)
SH_xy = [[1, 0, sh_x, 0],
         [0, 1, sh_y, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
         ]
print('SHx: ' + str(sh_x))
print('SHy: ' + str(sh_y))
print('SHxy: ' + str(SH_xy))
# return

# Sight volume is shifted so that the center is at the origin
T_parallel = ((-(r + l) / 2), (-(t + b) / 2), (-(n + f) / 2))
T_parallel_matrix = [[1, 0, 0, (-(r + l) / 2)],
                     [0, 1, 0, (-(t + b) / 2)],
                     [0, 0, 1, (-(n + f) / 2)],
                     [0, 0, 0, 1]
                     ]
# T_parallel_matrix = Mat4x4(a11=1, a12=0, a13=0, a14=3, a21=0, a22=1, a23=0, a24=3, a31=0, a32=0, a33=1, a34=3, a41=0, a42=0, a43=0, a44=1)

print("Tparallel: " + (str(T_parallel)))
print("Tparallel Matrix: " + (str(T_parallel_matrix)))
# return

# Convert visible volume to canonical visible volume
S_parallel = ((2 / (r - l)), (2 / (r - b)), (2 / (f - n)))
S_parallel_matrix = [[(2 / (r - l)), 0, 0, 0],
                     [0, (2 / (r - b)), 0, 0],
                     [0, 0, (2 / (f - n)), 0],
                     [0, 0, 0, 1]
                     ]
# S_parallel_matrix = Mat4x4((2 / (r - l)), 0, 0, 0, 0, (2 / (r - b)), 0, 0, 0, 0, (2 / (f - n)), 0, 0, 0, 0, 1)

print('Sparallel: ' + str(S_parallel))
print("Sparallel Matrix: " + (str(S_parallel_matrix)))
# return

# Total transformation sequence
# P_parallel = S_parallel_matrix * T_parallel_matrix * SH_xy * Rot_n_up_t * translation_matrix
P_parallel = S_parallel_matrix * T_parallel_matrix
print('Pparallel: ' + str(P_parallel))
# return


if __name__ == '__main__':
# Note: The following values are test values

P = Vec3(x=-1, y=-1, z=1)  # P = Camera Position
up = Vec3(x=0, y=1, z=0)  # up = Up Vector
normal = Vec3(x=0, y=0, z=-1)  # normal = Normal of the direction of view
v = (Vec3(x=0, y=0, z=0) - P)  # v = View
l = -4  # l = left
r = 2  # r = right
b = -3  # b = bottom
t = 2  # t = top
n = -1  # n = near
f = -99  # f = far

perspective_projection(P, up, normal, v, l, r, b, t, n, f)

When I run it, my output is the following:

Translationmatrix: [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, -1], [0, 0, 0, 1]]
z_strich: (0, 0, -1)
x_strich: (-1, 0, 0)
y_strich: (0, 1, 0)
Rotationsmatrix R(n, up): [[-1.0, 0.0, 0, 0], [0.0, 1.0, 0, 0], [0.0, 0.0, -1, 0], 
[0, 0, 0, 1]]
Inverse Rotationmatrix R(n, up)-1: [[-1.0, 0.0, 0.0, 0], [0.0, 1.0, 0.0, 0], [0, 0, 
-1, 0], [0, 0, 0, 1]]
Inverse Rotationmatrix R(n, up)T: [[-1. -0. -0. -0.]
[ 0.  1.  0.  0.]
[-0. -0. -1. -0.]
[ 0.  0.  0.  1.]]
Standard orientation: [[-1. -0. -0. -0.]
[ 0.  1.  0.  0.]
[-0. -0. -1.  0.]
[ 0.  0.  0.  1.]]
SHx: 1.0
SHy: 1.0
SHxy: [[1, 0, 1.0, 0], [0, 1, 1.0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
Tparallel: (1.0, 0.5, 50.0)
Tparallel Matrix: [[1, 0, 0, 1.0], [0, 1, 0, 0.5], [0, 0, 1, 50.0], [0, 0, 0, 1]]
Sparallel: (0.3333333333333333, 0.4, -0.02040816326530612)
Sparallel Matrix: [[0.3333333333333333, 0, 0, 0], [0, 0.4, 0, 0], [0, 0, 
-0.02040816326530612, 0], [0, 0, 0, 1]]

So you can see, that everything works completely fine - even S_parallel_matrix which has also some calculations in it (just like T_parallel_matrix which doesn't work). I also tried to put the matrix like this:

T_parallel_matrix = Mat4x4(a11=1, a12=0, a13=0, a14=3, a21=0, a22=1, a23=0, a24=3, a31=0, a32=0, a33=1, a34=3, a41=0, a42=0, a43=0, a44=1)

But when I run it, I get this error:

line 159, in perspective_projection
T_parallel_matrix = Mat4x4(a11=1, a12=0, a13=0, a14=3, a21=0, a22=1, a23=0, a24=3, a31=0, a32=0, a33=1, a34=3, a41=0, a42=0, a43=0, a44=1)

mat4x4.py", line 12, in __init__
self.a11 = a11, self.a12 = a12, self.a13 = a13, self.a14 = a14
TypeError: cannot unpack non-iterable int object

I believe that my mat4x4 class is somehow incorrect, but I'm not quite sure what the problem causes.

Can somebody explain why I get the first error (non int type) only with T_parallel_matrix?

This is my mat4x4.py with the Mat4x4 Class:

 from __future__ import annotations


 class Mat4x4:
 def __init__(self,
        a11: float, a12: float, a13: float, a14: float,
        a21: float, a22: float, a23: float, a24: float,
        a31: float, a32: float, a33: float, a34: float,
        a41: float, a42: float, a43: float, a44: float,
):
    self.a11 = a11, self.a12 = a12, self.a13 = a13, self.a14 = a14
    self.a21 = a21, self.a22 = a22, self.a23 = a23, self.a24 = a24
    self.a31 = a31, self.a32 = a32, self.a33 = a33, self.a34 = a34
    self.a41 = a41, self.a42 = a42, self.a43 = a43, self.a44 = a44

# Matrix multiplication
def __mul__(self, other: Mat4x4) -> Mat4x4:
    return Mat4x4(
        self.a11 * other.a11 + self.a12 * other.a21 + self.a13 * other.a31 + self.a14 * other.a41,  # a11
        self.a11 * other.a12 + self.a12 * other.a22 + self.a13 * other.a32 + self.a14 * other.a42,  # a12
        self.a11 * other.a13 + self.a12 * other.a23 + self.a13 * other.a33 + self.a14 * other.a43,  # a13
        self.a11 * other.a14 + self.a12 * other.a24 + self.a13 * other.a34 + self.a14 * other.a44,  # a14

        self.a21 * other.a11 + self.a22 * other.a12 + self.a23 * other.a13 + self.a24 * other.a14,  # a21
        self.a21 * other.a21 + self.a22 * other.a22 + self.a23 * other.a23 + self.a24 * other.a24,  # a22
        self.a21 * other.a31 + self.a22 * other.a32 + self.a23 * other.a33 + self.a24 * other.a34,  # a23
        self.a21 * other.a41 + self.a22 * other.a42 + self.a23 * other.a43 + self.a24 * other.a44,  # a24

        self.a31 * other.a11 + self.a32 * other.a12 + self.a33 * other.a13 + self.a34 * other.a14,  # a31
        self.a31 * other.a21 + self.a32 * other.a22 + self.a33 * other.a23 + self.a34 * other.a24,  # a32
        self.a31 * other.a31 + self.a32 * other.a32 + self.a33 * other.a33 + self.a34 * other.a34,  # a33
        self.a31 * other.a41 + self.a32 * other.a42 + self.a33 * other.a43 + self.a34 * other.a44,  # a34

        self.a41 * other.a11 + self.a42 * other.a12 + self.a43 * other.a13 + self.a44 * other.a14,  # a41
        self.a41 * other.a21 + self.a42 * other.a22 + self.a43 * other.a23 + self.a44 * other.a24,  # a42
        self.a41 * other.a31 + self.a42 * other.a32 + self.a43 * other.a33 + self.a44 * other.a34,  # a43
        self.a41 * other.a41 + self.a42 * other.a42 + self.a43 * other.a43 + self.a44 * other.a44,  # a44
    )

# Add
def __add__(self, other: Mat4x4) -> Mat4x4:
    return Mat4x4(
        self.a11 + other.a11,  # a11
        self.a12 + other.a12,  # a12
        self.a13 + other.a13,  # a13
        self.a14 + other.a14,  # a14

        self.a21 + other.a21,  # a21
        self.a22 + other.a22,  # a22
        self.a23 + other.a23,  # a23
        self.a24 + other.a24,  # a24

        self.a31 + other.a31,  # a31
        self.a32 + other.a32,  # a32
        self.a33 + other.a33,  # a33
        self.a34 + other.a34,  # a34

        self.a41 + other.a41,  # a41
        self.a42 + other.a42,  # a42
        self.a43 + other.a43,  # a43
        self.a44 + other.a44,  # a44
    )

# Subtract
def __sub__(self, other: Mat4x4) -> Mat4x4:
    return Mat4x4(
        self.a11 - other.a11,  # a11
        self.a12 - other.a12,  # a12
        self.a13 - other.a13,  # a13
        self.a14 - other.a14,  # a14

        self.a21 - other.a21,  # a21
        self.a22 - other.a22,  # a22
        self.a23 - other.a23,  # a23
        self.a24 - other.a24,  # a24

        self.a31 - other.a31,  # a31
        self.a32 - other.a32,  # a32
        self.a33 - other.a33,  # a33
        self.a34 - other.a34,  # a34

        self.a41 - other.a41,  # a41
        self.a42 - other.a42,  # a42
        self.a43 - other.a43,  # a43
        self.a44 - other.a44,  # a44
    )

# Not Equal
def __ne__(self) -> Mat4x4:
    return Mat4x4(
        -self.a11,  # a11
        -self.a12,  # a12
        -self.a13,  # a13
        -self.a14,  # a14

        -self.a21,  # a21
        -self.a22,  # a22
        -self.a23,  # a23
        -self.a24,  # a24

        -self.a31,  # a31
        -self.a32,  # a32
        -self.a33,  # a33
        -self.a34,  # a34

        -self.a41,  # a41
        -self.a42,  # a42
        -self.a43,  # a43
        -self.a44,  # a44
    )

# Convert to string
def __str__(self) -> str:
    return (
            f'{self.a11} {self.a12} {self.a13} {self.a14}\n' +
            f'{self.a21} {self.a22} {self.a23} {self.a24}\n' +
            f'{self.a31} {self.a32} {self.a33} {self.a34}\n' +
            f'{self.a41} {self.a42} {self.a43} {self.a44}'
    )

(If neccessary I can add the code for Vec3, but I think the problem ist with the mat4x4 class. )



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source