Module Matrix

Expand source code
# Copyright (C) 2024
# Wassim Jabi <wassim.jabi@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with
# this program. If not, see <https://www.gnu.org/licenses/>.

import math

class Matrix:
    @staticmethod
    def Add(matA, matB):
        """
        Description
        ----------
        Adds the two input matrices.
        
        Parameters
        ----------
        matA : list
            The first input matrix.
        matB : list
            The second input matrix.

        Returns
        -------
        list
            The matrix resulting from the addition of the two input matrices.

        """
        matC = []
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        for i in range(len(matA)):
            tempRow = []
            for j in range(len(matB)):
                tempRow.append(matA[i][j] + matB[i][j])
            matC.append(tempRow)
        return matC

    @staticmethod
    def ByRotation(angleX=0, angleY=0, angleZ=0, order="xyz"):
        """
        Description
        ----------
        Creates a 4x4 rotation matrix.

        Parameters
        ----------
        angleX : float , optional
            The desired rotation angle in degrees around the X axis. The default is 0.
        angleY : float , optional
            The desired rotation angle in degrees around the Y axis. The default is 0.
        angleZ : float , optional
            The desired rotation angle in degrees around the Z axis. The default is 0.
        order : string , optional
            The order by which the roatations will be applied. The possible values are any permutation of "xyz". This input is case insensitive. The default is "xyz".

        Returns
        -------
        list
            The created 4X4 rotation matrix.

        """
        def rotateXMatrix(radians):
            """ Return matrix for rotating about the x-axis by 'radians' radians """
            c = math.cos(radians)
            s = math.sin(radians)
            return [[1, 0, 0, 0],
                    [0, c,-s, 0],
                    [0, s, c, 0],
                    [0, 0, 0, 1]]

        def rotateYMatrix(radians):
            """ Return matrix for rotating about the y-axis by 'radians' radians """
            
            c = math.cos(radians)
            s = math.sin(radians)
            return [[ c, 0, s, 0],
                    [ 0, 1, 0, 0],
                    [-s, 0, c, 0],
                    [ 0, 0, 0, 1]]

        def rotateZMatrix(radians):
            """ Return matrix for rotating about the z-axis by 'radians' radians """
            
            c = math.cos(radians)
            s = math.sin(radians)
            return [[c,-s, 0, 0],
                    [s, c, 0, 0],
                    [0, 0, 1, 0],
                    [0, 0, 0, 1]]
        
        xMat = rotateXMatrix(math.radians(angleX))
        yMat = rotateYMatrix(math.radians(angleY))
        zMat = rotateZMatrix(math.radians(angleZ))
        if order.lower() == "xyz":
            return Matrix.Multiply(Matrix.Multiply(zMat,yMat),xMat)
        if order.lower() == "xzy":
            return Matrix.Multiply(Matrix.Multiply(yMat,zMat),xMat)
        if order.lower() == "yxz":
            return Matrix.Multiply(Matrix.Multiply(zMat,xMat),yMat)
        if order.lower == "yzx":
            return Matrix.Multiply(Matrix.Multiply(xMat,zMat),yMat)
        if order.lower() == "zxy":
            return Matrix.Multiply(Matrix.Multiply(yMat,xMat),zMat)
        if order.lower() == "zyx":
            return Matrix.Multiply(Matrix.Multiply(xMat,yMat),zMat)
    
    @staticmethod
    def ByScaling(scaleX=1.0, scaleY=1.0, scaleZ=1.0):
        """
        Description
        ----------
        Creates a 4x4 scaling matrix.

        Parameters
        ----------
        scaleX : float , optional
            The desired scaling factor along the X axis. The default is 1.
        scaleY : float , optional
            The desired scaling factor along the X axis. The default is 1.
        scaleZ : float , optional
            The desired scaling factor along the X axis. The default is 1.
        
        Returns
        -------
        list
            The created 4X4 scaling matrix.

        """
        return [[scaleX,0,0,0],
                [0,scaleY,0,0],
                [0,0,scaleZ,0],
                [0,0,0,1]]
    
    @staticmethod
    def ByTranslation(translateX=0, translateY=0, translateZ=0):
        """
        Description
        ----------
        Creates a 4x4 translation matrix.

        Parameters
        ----------
        translateX : float , optional
            The desired translation distance along the X axis. The default is 0.
        translateY : float , optional
            The desired translation distance along the X axis. The default is 0.
        translateZ : float , optional
            The desired translation distance along the X axis. The default is 0.
        
        Returns
        -------
        list
            The created 4X4 translation matrix.

        """
        return [[1,0,0,0],
                [0,1,0,0],
                [0,0,1,0],
                [translateX,translateY,translateZ,1]]
    
    @staticmethod
    def Multiply(matA, matB):
        """
        Description
        ----------
        Multiplies the two input matrices. When transforming an object, the first input matrix is applied first
        then the second input matrix.
        
        Parameters
        ----------
        matA : list
            The first input matrix.
        matB : list
            The second input matrix.

        Returns
        -------
        list
            The matrix resulting from the multiplication of the two input matrices.

        """
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        nr = len(matA)
        nc = len(matA[0])
        matC = []
        for i in range(nr):
            tempRow = []
            for j in range(nc):
                tempRow.append(0)
            matC.append(tempRow)
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        # iterate through rows of X
        for i in range(len(matA)):
            # iterate through columns of Y
            tempRow = []
            for j in range(len(matB[0])):
                # iterate through rows of Y
                for k in range(len(matB)):
                    matC[i][j] += matA[i][k] * matB[k][j]
        return matC

    @staticmethod
    def Subtract(matA, matB):
        """
        Description
        ----------
        Subtracts the two input matrices.
        
        Parameters
        ----------
        matA : list
            The first input matrix.
        matB : list
            The second input matrix.

        Returns
        -------
        list
            The matrix resulting from the subtraction of the second input matrix from the first input matrix.

        """
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        matC = []
        for i in range(len(matA)):
            tempRow = []
            for j in range(len(matB)):
                tempRow.append(matA[i][j] - matB[i][j])
            matC.append(tempRow)
        return matC

    @staticmethod
    def Transpose(matrix):
        """
        Description
        ----------
        Transposes the input matrix.
        
        Parameters
        ----------
        matrix : list
            The input matrix.

        Returns
        -------
        list
            The transposed matrix.

        """
        return [list(x) for x in zip(*matrix)]

Classes

class Matrix
Expand source code
class Matrix:
    @staticmethod
    def Add(matA, matB):
        """
        Description
        ----------
        Adds the two input matrices.
        
        Parameters
        ----------
        matA : list
            The first input matrix.
        matB : list
            The second input matrix.

        Returns
        -------
        list
            The matrix resulting from the addition of the two input matrices.

        """
        matC = []
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        for i in range(len(matA)):
            tempRow = []
            for j in range(len(matB)):
                tempRow.append(matA[i][j] + matB[i][j])
            matC.append(tempRow)
        return matC

    @staticmethod
    def ByRotation(angleX=0, angleY=0, angleZ=0, order="xyz"):
        """
        Description
        ----------
        Creates a 4x4 rotation matrix.

        Parameters
        ----------
        angleX : float , optional
            The desired rotation angle in degrees around the X axis. The default is 0.
        angleY : float , optional
            The desired rotation angle in degrees around the Y axis. The default is 0.
        angleZ : float , optional
            The desired rotation angle in degrees around the Z axis. The default is 0.
        order : string , optional
            The order by which the roatations will be applied. The possible values are any permutation of "xyz". This input is case insensitive. The default is "xyz".

        Returns
        -------
        list
            The created 4X4 rotation matrix.

        """
        def rotateXMatrix(radians):
            """ Return matrix for rotating about the x-axis by 'radians' radians """
            c = math.cos(radians)
            s = math.sin(radians)
            return [[1, 0, 0, 0],
                    [0, c,-s, 0],
                    [0, s, c, 0],
                    [0, 0, 0, 1]]

        def rotateYMatrix(radians):
            """ Return matrix for rotating about the y-axis by 'radians' radians """
            
            c = math.cos(radians)
            s = math.sin(radians)
            return [[ c, 0, s, 0],
                    [ 0, 1, 0, 0],
                    [-s, 0, c, 0],
                    [ 0, 0, 0, 1]]

        def rotateZMatrix(radians):
            """ Return matrix for rotating about the z-axis by 'radians' radians """
            
            c = math.cos(radians)
            s = math.sin(radians)
            return [[c,-s, 0, 0],
                    [s, c, 0, 0],
                    [0, 0, 1, 0],
                    [0, 0, 0, 1]]
        
        xMat = rotateXMatrix(math.radians(angleX))
        yMat = rotateYMatrix(math.radians(angleY))
        zMat = rotateZMatrix(math.radians(angleZ))
        if order.lower() == "xyz":
            return Matrix.Multiply(Matrix.Multiply(zMat,yMat),xMat)
        if order.lower() == "xzy":
            return Matrix.Multiply(Matrix.Multiply(yMat,zMat),xMat)
        if order.lower() == "yxz":
            return Matrix.Multiply(Matrix.Multiply(zMat,xMat),yMat)
        if order.lower == "yzx":
            return Matrix.Multiply(Matrix.Multiply(xMat,zMat),yMat)
        if order.lower() == "zxy":
            return Matrix.Multiply(Matrix.Multiply(yMat,xMat),zMat)
        if order.lower() == "zyx":
            return Matrix.Multiply(Matrix.Multiply(xMat,yMat),zMat)
    
    @staticmethod
    def ByScaling(scaleX=1.0, scaleY=1.0, scaleZ=1.0):
        """
        Description
        ----------
        Creates a 4x4 scaling matrix.

        Parameters
        ----------
        scaleX : float , optional
            The desired scaling factor along the X axis. The default is 1.
        scaleY : float , optional
            The desired scaling factor along the X axis. The default is 1.
        scaleZ : float , optional
            The desired scaling factor along the X axis. The default is 1.
        
        Returns
        -------
        list
            The created 4X4 scaling matrix.

        """
        return [[scaleX,0,0,0],
                [0,scaleY,0,0],
                [0,0,scaleZ,0],
                [0,0,0,1]]
    
    @staticmethod
    def ByTranslation(translateX=0, translateY=0, translateZ=0):
        """
        Description
        ----------
        Creates a 4x4 translation matrix.

        Parameters
        ----------
        translateX : float , optional
            The desired translation distance along the X axis. The default is 0.
        translateY : float , optional
            The desired translation distance along the X axis. The default is 0.
        translateZ : float , optional
            The desired translation distance along the X axis. The default is 0.
        
        Returns
        -------
        list
            The created 4X4 translation matrix.

        """
        return [[1,0,0,0],
                [0,1,0,0],
                [0,0,1,0],
                [translateX,translateY,translateZ,1]]
    
    @staticmethod
    def Multiply(matA, matB):
        """
        Description
        ----------
        Multiplies the two input matrices. When transforming an object, the first input matrix is applied first
        then the second input matrix.
        
        Parameters
        ----------
        matA : list
            The first input matrix.
        matB : list
            The second input matrix.

        Returns
        -------
        list
            The matrix resulting from the multiplication of the two input matrices.

        """
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        nr = len(matA)
        nc = len(matA[0])
        matC = []
        for i in range(nr):
            tempRow = []
            for j in range(nc):
                tempRow.append(0)
            matC.append(tempRow)
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        # iterate through rows of X
        for i in range(len(matA)):
            # iterate through columns of Y
            tempRow = []
            for j in range(len(matB[0])):
                # iterate through rows of Y
                for k in range(len(matB)):
                    matC[i][j] += matA[i][k] * matB[k][j]
        return matC

    @staticmethod
    def Subtract(matA, matB):
        """
        Description
        ----------
        Subtracts the two input matrices.
        
        Parameters
        ----------
        matA : list
            The first input matrix.
        matB : list
            The second input matrix.

        Returns
        -------
        list
            The matrix resulting from the subtraction of the second input matrix from the first input matrix.

        """
        if not isinstance(matA, list):
            return None
        if not isinstance(matB, list):
            return None
        matC = []
        for i in range(len(matA)):
            tempRow = []
            for j in range(len(matB)):
                tempRow.append(matA[i][j] - matB[i][j])
            matC.append(tempRow)
        return matC

    @staticmethod
    def Transpose(matrix):
        """
        Description
        ----------
        Transposes the input matrix.
        
        Parameters
        ----------
        matrix : list
            The input matrix.

        Returns
        -------
        list
            The transposed matrix.

        """
        return [list(x) for x in zip(*matrix)]

Static methods

def Add(matA, matB)

Description

Adds the two input matrices.

Parameters

matA : list
The first input matrix.
matB : list
The second input matrix.

Returns

list
The matrix resulting from the addition of the two input matrices.
Expand source code
@staticmethod
def Add(matA, matB):
    """
    Description
    ----------
    Adds the two input matrices.
    
    Parameters
    ----------
    matA : list
        The first input matrix.
    matB : list
        The second input matrix.

    Returns
    -------
    list
        The matrix resulting from the addition of the two input matrices.

    """
    matC = []
    if not isinstance(matA, list):
        return None
    if not isinstance(matB, list):
        return None
    for i in range(len(matA)):
        tempRow = []
        for j in range(len(matB)):
            tempRow.append(matA[i][j] + matB[i][j])
        matC.append(tempRow)
    return matC
def ByRotation(angleX=0, angleY=0, angleZ=0, order='xyz')

Description

Creates a 4x4 rotation matrix.

Parameters

angleX : float , optional
The desired rotation angle in degrees around the X axis. The default is 0.
angleY : float , optional
The desired rotation angle in degrees around the Y axis. The default is 0.
angleZ : float , optional
The desired rotation angle in degrees around the Z axis. The default is 0.
order : string , optional
The order by which the roatations will be applied. The possible values are any permutation of "xyz". This input is case insensitive. The default is "xyz".

Returns

list
The created 4X4 rotation matrix.
Expand source code
@staticmethod
def ByRotation(angleX=0, angleY=0, angleZ=0, order="xyz"):
    """
    Description
    ----------
    Creates a 4x4 rotation matrix.

    Parameters
    ----------
    angleX : float , optional
        The desired rotation angle in degrees around the X axis. The default is 0.
    angleY : float , optional
        The desired rotation angle in degrees around the Y axis. The default is 0.
    angleZ : float , optional
        The desired rotation angle in degrees around the Z axis. The default is 0.
    order : string , optional
        The order by which the roatations will be applied. The possible values are any permutation of "xyz". This input is case insensitive. The default is "xyz".

    Returns
    -------
    list
        The created 4X4 rotation matrix.

    """
    def rotateXMatrix(radians):
        """ Return matrix for rotating about the x-axis by 'radians' radians """
        c = math.cos(radians)
        s = math.sin(radians)
        return [[1, 0, 0, 0],
                [0, c,-s, 0],
                [0, s, c, 0],
                [0, 0, 0, 1]]

    def rotateYMatrix(radians):
        """ Return matrix for rotating about the y-axis by 'radians' radians """
        
        c = math.cos(radians)
        s = math.sin(radians)
        return [[ c, 0, s, 0],
                [ 0, 1, 0, 0],
                [-s, 0, c, 0],
                [ 0, 0, 0, 1]]

    def rotateZMatrix(radians):
        """ Return matrix for rotating about the z-axis by 'radians' radians """
        
        c = math.cos(radians)
        s = math.sin(radians)
        return [[c,-s, 0, 0],
                [s, c, 0, 0],
                [0, 0, 1, 0],
                [0, 0, 0, 1]]
    
    xMat = rotateXMatrix(math.radians(angleX))
    yMat = rotateYMatrix(math.radians(angleY))
    zMat = rotateZMatrix(math.radians(angleZ))
    if order.lower() == "xyz":
        return Matrix.Multiply(Matrix.Multiply(zMat,yMat),xMat)
    if order.lower() == "xzy":
        return Matrix.Multiply(Matrix.Multiply(yMat,zMat),xMat)
    if order.lower() == "yxz":
        return Matrix.Multiply(Matrix.Multiply(zMat,xMat),yMat)
    if order.lower == "yzx":
        return Matrix.Multiply(Matrix.Multiply(xMat,zMat),yMat)
    if order.lower() == "zxy":
        return Matrix.Multiply(Matrix.Multiply(yMat,xMat),zMat)
    if order.lower() == "zyx":
        return Matrix.Multiply(Matrix.Multiply(xMat,yMat),zMat)
def ByScaling(scaleX=1.0, scaleY=1.0, scaleZ=1.0)

Description

Creates a 4x4 scaling matrix.

Parameters

scaleX : float , optional
The desired scaling factor along the X axis. The default is 1.
scaleY : float , optional
The desired scaling factor along the X axis. The default is 1.
scaleZ : float , optional
The desired scaling factor along the X axis. The default is 1.

Returns

list
The created 4X4 scaling matrix.
Expand source code
@staticmethod
def ByScaling(scaleX=1.0, scaleY=1.0, scaleZ=1.0):
    """
    Description
    ----------
    Creates a 4x4 scaling matrix.

    Parameters
    ----------
    scaleX : float , optional
        The desired scaling factor along the X axis. The default is 1.
    scaleY : float , optional
        The desired scaling factor along the X axis. The default is 1.
    scaleZ : float , optional
        The desired scaling factor along the X axis. The default is 1.
    
    Returns
    -------
    list
        The created 4X4 scaling matrix.

    """
    return [[scaleX,0,0,0],
            [0,scaleY,0,0],
            [0,0,scaleZ,0],
            [0,0,0,1]]
def ByTranslation(translateX=0, translateY=0, translateZ=0)

Description

Creates a 4x4 translation matrix.

Parameters

translateX : float , optional
The desired translation distance along the X axis. The default is 0.
translateY : float , optional
The desired translation distance along the X axis. The default is 0.
translateZ : float , optional
The desired translation distance along the X axis. The default is 0.

Returns

list
The created 4X4 translation matrix.
Expand source code
@staticmethod
def ByTranslation(translateX=0, translateY=0, translateZ=0):
    """
    Description
    ----------
    Creates a 4x4 translation matrix.

    Parameters
    ----------
    translateX : float , optional
        The desired translation distance along the X axis. The default is 0.
    translateY : float , optional
        The desired translation distance along the X axis. The default is 0.
    translateZ : float , optional
        The desired translation distance along the X axis. The default is 0.
    
    Returns
    -------
    list
        The created 4X4 translation matrix.

    """
    return [[1,0,0,0],
            [0,1,0,0],
            [0,0,1,0],
            [translateX,translateY,translateZ,1]]
def Multiply(matA, matB)

Description

Multiplies the two input matrices. When transforming an object, the first input matrix is applied first then the second input matrix.

Parameters

matA : list
The first input matrix.
matB : list
The second input matrix.

Returns

list
The matrix resulting from the multiplication of the two input matrices.
Expand source code
@staticmethod
def Multiply(matA, matB):
    """
    Description
    ----------
    Multiplies the two input matrices. When transforming an object, the first input matrix is applied first
    then the second input matrix.
    
    Parameters
    ----------
    matA : list
        The first input matrix.
    matB : list
        The second input matrix.

    Returns
    -------
    list
        The matrix resulting from the multiplication of the two input matrices.

    """
    if not isinstance(matA, list):
        return None
    if not isinstance(matB, list):
        return None
    nr = len(matA)
    nc = len(matA[0])
    matC = []
    for i in range(nr):
        tempRow = []
        for j in range(nc):
            tempRow.append(0)
        matC.append(tempRow)
    if not isinstance(matA, list):
        return None
    if not isinstance(matB, list):
        return None
    # iterate through rows of X
    for i in range(len(matA)):
        # iterate through columns of Y
        tempRow = []
        for j in range(len(matB[0])):
            # iterate through rows of Y
            for k in range(len(matB)):
                matC[i][j] += matA[i][k] * matB[k][j]
    return matC
def Subtract(matA, matB)

Description

Subtracts the two input matrices.

Parameters

matA : list
The first input matrix.
matB : list
The second input matrix.

Returns

list
The matrix resulting from the subtraction of the second input matrix from the first input matrix.
Expand source code
@staticmethod
def Subtract(matA, matB):
    """
    Description
    ----------
    Subtracts the two input matrices.
    
    Parameters
    ----------
    matA : list
        The first input matrix.
    matB : list
        The second input matrix.

    Returns
    -------
    list
        The matrix resulting from the subtraction of the second input matrix from the first input matrix.

    """
    if not isinstance(matA, list):
        return None
    if not isinstance(matB, list):
        return None
    matC = []
    for i in range(len(matA)):
        tempRow = []
        for j in range(len(matB)):
            tempRow.append(matA[i][j] - matB[i][j])
        matC.append(tempRow)
    return matC
def Transpose(matrix)

Description

Transposes the input matrix.

Parameters

matrix : list
The input matrix.

Returns

list
The transposed matrix.
Expand source code
@staticmethod
def Transpose(matrix):
    """
    Description
    ----------
    Transposes the input matrix.
    
    Parameters
    ----------
    matrix : list
        The input matrix.

    Returns
    -------
    list
        The transposed matrix.

    """
    return [list(x) for x in zip(*matrix)]