# BRL.Matrix

Matrices are fundamental mathematical constructs used in various fields, such as computer graphics, physics simulations, and linear algebra. They are especially useful for representing linear transformations, including rotations, translations, and scaling operations. In the context of graphics and 3D geometry, matrices are commonly used to manipulate vertices and objects in a scene, transforming their coordinates and orientations.

A matrix is a rectangular array of numbers, organized into rows and columns. In BlitzMax,
`brl.matrix`

provides several structs to work with matrices of different
sizes and types, such as SMat2D, SMat3D, SMat4D, SMat2F, SMat3F, SMat4F, SMat2I, SMat3I, and SMat4I.
The name of each struct indicates its size and the primitive type it uses: Double, Float, or Int.
In our examples, we'll focus primarily on the Double structs, but the same concepts apply to the other
structs as well.

The following is a brief introduction to the three main types of matrices used in graphics and 3D geometry, which BlitzMax provides structs for, along with a high-level overview of their applications:

## Types of Matrices

### 2x2 Matrices

A 2x2 matrix, represented by the SMat2D, SMat2F and SMat2I structs, is primarily used for 2D linear transformations, such as rotation and scaling. These matrices can be applied to 2D vectors, transforming their coordinates accordingly. For example, a 2x2 rotation matrix can be used to rotate a 2D vector around the origin by a specified angle.

### 3x3 Matrices

3x3 matrices, represented by the SMat3D, SMat3F and SMat3I structs, are commonly used for 3D linear transformations that do not involve translation, such as rotation and scaling. These matrices can be applied to 3D vectors, transforming their coordinates without changing their position in the scene. For example, a 3x3 rotation matrix can be used to rotate a 3D vector around a specific axis by a given angle.

The following example demonstrates the use of 3x3 matrices, by creating a simple solar system. The sun is represented by a yellow circle, and the planets are represented by blue circles. The planets are rotating around the sun, and their positions are calculated using 3x3 matrices.

```
SuperStrict
Framework SDL.SDLRenderMax2D
Import brl.matrix
Graphics 800, 600, 0
Local sunX:Float = GraphicsWidth() / 2
Local sunY:Float = GraphicsHeight() / 2
Local sunRadius:Float = 50
Local planets:TPlanet[] = [New TPlanet(150, 20, 0.7), New TPlanet(200, 15, 0.5), New TPlanet(250, 10, 0.3)]
While Not KeyHit(KEY_ESCAPE)
Cls
' Draw the sun
SetColor(255, 255, 0)
DrawOval(sunX - sunRadius, sunY - sunRadius, sunRadius * 2, sunRadius * 2)
' Draw the planets
For Local planet:TPlanet = EachIn planets
planet.Draw(sunX, sunY)
Next
Flip
Wend
Type TPlanet
Field distance:Float
Field radius:Float
Field angle:Float
Field speed:Float
Method New(distance:Float, radius:Float, speed:Float)
Self.distance = distance
Self.radius = radius
Self.speed = speed
End Method
Method Draw(centerX:Float, centerY:Float)
' Calculate the planet's position
Local planetMatrix:SMat3D = SMat3D.Identity()
planetMatrix = planetMatrix.Rotate(angle)
planetMatrix = planetMatrix.Translate(New SVec3D(distance, 0, 0))
Local planetPos:SVec3D = planetMatrix.Apply(New SVec3D(0, 0, 1))
' Draw the planet
SetColor(0, 0, 255)
DrawOval(Float(centerX + planetPos.x - radius), Float(centerY + planetPos.y - radius), radius * 2, radius * 2)
' Update the angle for the next frame
angle :+ speed
End Method
End Type
```

### 4x4 Matrices

4x4 matrices, represented by the SMat4D, SMat4F and SMat4I structs, are the most versatile and widely used matrices in 3D graphics. They can represent any combination of linear transformations, such as rotation, scaling, and translation. A 4x4 matrix can be applied to a 3D vector, transforming its position, orientation, and scale in the scene. For example, a 4x4 transformation matrix can be used to move an object in 3D space, rotate it around a specific axis, and scale it uniformly or non-uniformly.

Creating a 3D-like effect in 2D can be achieved using simple orthogonal projection. In this example, we will create a rotating cube using a 4x4 transformation matrix to apply rotation, scaling, and translation.

```
SuperStrict
Framework SDL.SDLRenderMax2D
Import brl.matrix
Graphics 800, 600, 0
Local cube:TCube = New TCube
Local angle:Float = 0
Local centerX:Int = GraphicsWidth() / 2
Local centerY:Int = GraphicsHeight() / 2
While Not KeyHit(KEY_ESCAPE)
Cls
' Create the transformation matrix..
' Start with an identity matrix as the initial transformation.
Local matrix:SMat4D = SMat4D.Identity()
' Move the object away from the camera along the Z-axis by a distance of 6 units.
' This translation ensures that the object is visible and centered in the view.
matrix = matrix.Translate(New SVec3D(0, 0, -6))
' Rotate the object around the Z-axis (blue axis) by an angle scaled by 1.2.
' This rotation is applied first to achieve a "rolling" effect.
matrix = matrix.Rotate(New SVec3D(0, 0, 1), angle * 1.2)
' Rotate the object around the Y-axis (green axis) by an angle scaled by 0.7.
' This rotation is applied after the first rotation, creating a "pitching" effect.
matrix = matrix.Rotate(New SVec3D(0, 1, 0), angle * 0.7)
' Finally, rotate the object around the X-axis (red axis) by the base angle.
' This rotation is applied last, creating a "yawing" effect.
matrix = matrix.Rotate(New SVec3D(1, 0, 0), angle)
' Draw cube
cube.Draw(matrix, 100, centerX, centerY)
Flip
angle :+ 0.5
Wend
Type TCube
Field vertices:Float[24] ' 8 vertices, each with 3 coordinates
Field edges:Int[24] ' 12 edges, each with 2 vertex indices
Method New()
vertices = [ -1:Float, -1:Float, -1:Float, 1:Float, -1:Float, -1:Float, 1:Float, 1:Float, -1:Float, -1:Float, ..
1:Float, -1:Float, -1:Float, -1:Float, 1:Float, 1:Float, -1:Float, 1:Float, 1:Float, 1:Float, ..
1:Float, -1:Float, 1:Float, 1:Float ]
edges = [ 0, 1, 1, 2, 2, 3, 3, 0, ..
4, 5, 5, 6, 6, 7, 7, 4, ..
0, 4, 1, 5, 2, 6, 3, 7 ]
End Method
Method Draw(matrix:SMat4D, scale:Float = 1, centerX:Int, centerY:Int)
Local transformedVertices:Float[24]
' Apply transformation and orthographic projection
For Local i:Int = 0 Until 24 Step 3
Local vertex:SVec3D = New SVec3D(vertices[i], vertices[i + 1], vertices[i + 2])
vertex = matrix.Apply(vertex)
transformedVertices[i] = centerX + (scale * vertex.x)
transformedVertices[i + 1] = centerY - (scale * vertex.y)
Next
' Draw edges
For Local i:Int = 0 Until 24 Step 2
DrawLine(transformedVertices[edges[i] * 3], transformedVertices[edges[i] * 3 + 1],
transformedVertices[edges[i + 1] * 3], transformedVertices[edges[i + 1] * 3 + 1])
Next
End Method
End Type
```

## Column-Major vs. Row-Major Matrices

In `brl.matrix`

, we use column-major ordering for matrices. Column-major ordering is a convention
in which elements are stored column by column in memory. It is the opposite of row-major ordering, where
elements are stored row by row. This distinction is important when performing operations like matrix
multiplication or when applying transformations to vectors or other matrices.

Column-major ordering is commonly used in graphics programming and some mathematical libraries. In this convention, when applying transformations, the order in which they are applied is reversed compared to row-major ordering. This means that when you want to apply multiple transformations, you should apply them in the reverse order that you would with row-major ordering.

For example, in column-major ordering, to rotate an object around the X, Y, and Z axes and then translate it, you would first apply the translation, then the rotation around the Z axis, followed by the rotation around the Y axis, and finally the rotation around the X axis.

## Determinant, Inverse, and Transpose in Matrices

### Determinant

The determinant is a scalar value associated with square matrices that carries essential information about the matrix's properties. It has several important geometric interpretations and applications in linear algebra.

In the context of 2D transformations, the determinant represents the area scaling factor when a matrix is applied to a vector. If the determinant is positive, the transformation preserves the orientation; if it's negative, the orientation is reversed. A determinant equal to zero indicates that the transformation collapses the vector onto a lower-dimensional subspace (e.g., a line or a point), making the matrix singular and non-invertible.

Mathematically, the determinant of a 2x2 matrix is calculated as follows:

```
|A| = |a b|
|c d|
|A| = ad - bc
```

Here's an example illustrating how to calculate the determinant of a 2x2 matrix using the SMat2D struct:

```
SuperStrict
Framework BRL.StandardIO
Import BRL.Matrix
' Define matrix elements
Local a:Double = 3.0
Local b:Double = 2.0
Local c:Double = 5.0
Local d:Double = 4.0
' Create a 2x2 matrix
Local mat:SMat2D = New SMat2D(a, b, c, d)
' Calculate the determinant
Local det:Double = mat.Determinant()
' Print the determinant
Print "Determinant: " + det
```

When you run this example, it will create a 2x2 matrix with the specified elements,
calculate the determinant using the `Determinant()`

method provided by SMat2D, and print the resulting
determinant value. In this case, the output will be:

```
Determinant: -2.0
```

For a 3x3 matrix, the determinant can be calculated using the following formula:

```
|A| = |a b c|
|d e f|
|g h i|
|A| = a(ei - fh) - b(di - fg) + c(dh - eg)
```

Here's an example illustrating how to calculate the determinant of a 3x3 matrix using the SMat3D struct:

```
SuperStrict
Framework BRL.StandardIO
Import BRL.Matrix
' Define matrix elements
Local a:Double = 1.0
Local b:Double = 2.0
Local c:Double = 3.0
Local d:Double = 4.0
Local e:Double = 5.0
Local f:Double = 6.0
Local g:Double = 7.0
Local h:Double = 8.0
Local i:Double = 9.0
' Create a 3x3 matrix
Local mat:SMat3D = New SMat3D(a, b, c, d, e, f, g, h, i)
' Calculate the determinant
Local det:Double = mat.Determinant()
' Print the determinant
Print "Determinant: " + det
```

When you run this example, it will create a 3x3 matrix with the specified elements,
calculate the determinant using the `Determinant()`

method provided by SMat3D, and print the
resulting determinant value. In this case, the output will be:

```
Determinant: 0.0
```

### Inverse

The inverse of a matrix is another matrix that, when multiplied with the original matrix, results in the identity matrix. In other words, for a matrix A, its inverse A⁻¹ exists if and only if A * A⁻¹ = A⁻¹ * A = I, where I is the identity matrix. Not all matrices have inverses; only square matrices (i.e., matrices with the same number of rows and columns) may have inverses, and even then, not all square matrices are invertible.

For a 2x2 matrix:

```
| a b |
| c d |
```

The inverse can be calculated using the following formula:

```
1 / (ad - bc) * | d -b |
| -c a |
```

The term (ad - bc) is the determinant of the matrix. If the determinant is zero, the matrix is singular and does not have an inverse.

For a 3x3 matrix, the process is more complicated and involves finding the matrix of minors, the matrix of cofactors, and finally, the adjugate matrix. The inverse can then be computed by dividing the adjugate matrix by the determinant of the original matrix.

Here is an example for finding the inverse of a 2x2 matrix using the SMat2D struct:

```
SuperStrict
Framework brl.standardio
Import brl.matrix
' Create a 2x2 matrix
Local a:Double = 3
Local b:Double = 2
Local c:Double = 5
Local d:Double = 3
Local mat:SMat2D = New SMat2D(a, b, c, d)
' Calculate the inverse
Local matInverse:SMat2D = mat.Invert()
' Print the original and inverse matrices
Print "Original matrix:~n" + mat.ToString()
Print "Inverse matrix:~n" + matInverse.ToString()
```

When you run this example, it will output the original 2x2 matrix and its inverse:

```
Original matrix:
3.000 2.000
5.000 3.000
Inverse matrix:
-1.000 0.667
1.667 -1.000
```

And here is an example for finding the inverse of a 3x3 matrix using the SMat3D struct:

```
SuperStrict
Framework brl.standardio
Import brl.matrix
' Create a 3x3 matrix
Local a:Double = 1
Local b:Double = 2
Local c:Double = 3
Local d:Double = 0
Local e:Double = 1
Local f:Double = 4
Local g:Double = 5
Local h:Double = 6
Local i:Double = 0
Local mat:SMat3D = New SMat3D(a, b, c, d, e, f, g, h, i)
' Calculate the inverse
Local matInverse:SMat3D = mat.Invert()
' Print the original and inverse matrices
Print "Original matrix: " + mat.ToString()
Print "Inverse matrix: " + matInverse.ToString()
```

When you run this example, it will output the original 3x3 matrix and its inverse:

```
Original matrix:
1.000 2.000 3.000
0.000 1.000 4.000
5.000 6.000 0.000
Inverse matrix:
-24.000 18.000 5.000
20.000 -15.000 -4.000
-5.000 4.000 1.000
```

### Transpose

The transpose of a matrix is a new matrix obtained by interchanging its rows and columns. In other words, the transpose of a matrix A is a new matrix Aᵀ, where the element Aᵀ[i, j] = A[j, i]. The transpose operation has several important properties and applications in linear algebra, including simplifying matrix equations and working with symmetric matrices.

For a 2x2 matrix A:

```
A = |a b| Aᵀ = |a c|
|c d| |b d|
```

For a 3x3 matrix A:

```
A = |a b c| Aᵀ = |a d g|
|d e f| |b e h|
|g h i| |c f i|
```

Here's an example illustrating how to calculate the transpose of a 2x2 matrix using the SMat2D struct.

```
SuperStrict
Framework brl.standardIO
Import brl.matrix
' Define matrix elements
Local a:Double = 1.0
Local b:Double = 2.0
Local c:Double = 3.0
Local d:Double = 4.0
' Create a 2x2 matrix
Local mat:SMat2D = New SMat2D(a, b, c, d)
' Calculate the transpose
Local matTranspose:SMat2D = mat.Transpose()
' Print the original and transposed matrices
Print "Original matrix:~n" + mat.ToString()
Print "Transposed matrix:~n" + matTranspose.ToString()
```

When you run this example, it will create a 2x2 matrix with the specified elements, calculate the transpose using the Transpose() method provided by the SMat2D struct, and print the original and transposed matrices. In this case, the output will be:

```
Original matrix:
1.0, 2.0
3.0, 4.0
Transposed matrix:
1.0 3.0
2.0 4.0
```

And an example for calculating the transpose of a 3x3 matrix using the SMat3D struct.

```
SuperStrict
Framework brl.standardIO
Import brl.matrix
' Define matrix elements
Local a:Double = 1.0
Local b:Double = 2.0
Local c:Double = 3.0
Local d:Double = 4.0
Local e:Double = 5.0
Local f:Double = 6.0
Local g:Double = 7.0
Local h:Double = 8.0
Local i:Double = 9.0
' Create a 3x3 matrix
Local mat:SMat3D = New SMat3D(a, b, c, d, e, f, g, h, i)
' Calculate the transpose
Local matTranspose:SMat3D = mat.Transpose()
' Print the original and transposed matrices
Print "Original matrix: " + mat.ToString()
Print "Transposed matrix: " + matTranspose.ToString()
```

When you run this example, it will create a 3x3 matrix with the specified elements, calculate the transpose using the Transpose() method provided by the SMat3D struct, and print the original and transposed matrices. In this case, the output will be:

```
Original matrix:
1.0 2.0 3.0
4.0 5.0 6.0
7.0 8.0 9.0
Transposed matrix:
1.0 4.0 7.0
2.0 5.0 8.0
3.0 6.0 9.0
```

Understanding the transpose concept and its properties is important when working with matrices in your BlitzMax projects. The transpose operation can help simplify matrix equations and work with symmetric matrices, among other applications. By transposing a matrix, you can manipulate its elements and apply various transformations as required in your project.

## Scaling, rotation, and shearing matrices

Scaling, rotation, and shearing matrices are fundamental linear transformations used in various fields, such as computer graphics, physics simulations, and geometric modeling. These transformations can be applied to vectors or points to change their position, orientation, or shape.

### Scaling matrices

Scaling is the process of resizing an object uniformly or non-uniformly along its axes. Scaling matrices are diagonal matrices that have scaling factors along the diagonal elements, and zeros elsewhere.

For 2D scaling:

```
| sx 0 |
| 0 sy |
```

For 3D scaling:

```
| sx 0 0 |
| 0 sy 0 |
| 0 0 sz |
```

Here, sx, sy, and sz are the scaling factors along the x, y, and z axes, respectively. To apply the scaling transformation, you multiply the scaling matrix by the vector or point you want to scale.

### Rotation matrices

Rotation is the process of rotating an object around a point or an axis. Rotation matrices are used to represent the rotation transformations in both 2D and 3D spaces.

For 2D rotation around the origin by angle θ:

```
| cos(θ) -sin(θ) |
| sin(θ) cos(θ) |
```

For 3D rotation around an arbitrary axis (x, y, z) by angle θ, the rotation matrix is more complex. One common method is using the axis-angle representation, which involves the Rodrigues' rotation formula. The formula for the 3D rotation matrix is as follows:

```
R = I + sin(θ) * K + (1 - cos(θ)) * K^2
```

Where `I`

is the identity matrix, `θ`

is the angle of rotation, and `K`

is the skew-symmetric matrix representation of the axis vector.

### Shearing matrices

Shearing is the process of transforming an object by displacing its points along one axis based on the displacement of points along a parallel axis. Shearing matrices are used to represent these transformations.

For 2D shearing:

```
| 1 shx |
| shy 1 |
```

For 3D shearing along the x-axis:

```
| 1 shy shz |
| 0 1 0 |
| 0 0 1 |
```

And similar matrices can be defined for shearing along the y-axis and z-axis. Here, `shx`

, `shy`

, and `shz`

represent the shearing factors.

When applying these transformations, it's important to consider the order of operations, as matrix multiplication is not commutative. Typically, scaling and shearing are applied first, followed by rotation, and finally translation. Also, remember that these matrices should be applied to homogeneous coordinates for translation to work correctly. In 3D graphics, this often involves using 4x4 matrices with an additional row and column for the homogeneous coordinate.

## Matrix multiplication

Matrix multiplication is an essential operation in linear algebra and has numerous applications in computer graphics, physics, and other fields. Multiplying two matrices involves specific rules, and it's important to understand the dimensions of the matrices and how to perform the multiplication element-wise.

### Rules for Matrix Multiplication

Given two matrices A and B, the product AB can only be computed if the number of columns in A is equal to the number of rows in B. If matrix A has dimensions m × n and matrix B has dimensions n × p, then the product AB will have dimensions m × p.

`(AB)_ij = A_i1 * B_1j + A_i2 * B_2j + ... + A_in * B_nj`

where (AB)_ij represents the element in the i-th row and j-th column of the resulting matrix AB.

### Element-wise matrix multiplication

To multiply two matrices element-wise, follow these steps:

Verify that the dimensions of the matrices are compatible for multiplication. The number of columns in matrix A must be equal to the number of rows in matrix B.

Create a new matrix C with dimensions m × p, where m is the number of rows in matrix A and p is the number of columns in matrix B.

For each element (i, j) in the resulting matrix C, calculate the value as the sum of the products of the corresponding row elements in matrix A and the column elements in matrix B:

`C_ij = A_i1 * B_1j + A_i2 * B_2j + ... + A_in * B_nj`

Iterate through all elements in matrix C, computing their values using the above formula.The resulting matrix C represents the product of matrices A and B.

It's important to note that matrix multiplication is not commutative, meaning that AB ≠ BA in general. However, it is associative (A(BC) = (AB)C) and distributive over addition (A(B+C) = AB + AC).

The `CompMul()`

method can be used to perform element-wise matrix multiplication.

### Matrix multiplication using the dot product

Matrix multiplication is a fundamental operation in linear algebra, and it is performed using the dot product. It is important to understand that matrix multiplication is not the same as element-wise multiplication. In matrix multiplication, the dot product of the rows of the first matrix and the columns of the second matrix is used to calculate the resulting matrix elements.

Consider two matrices, A and B, where A has dimensions m x n (m rows and n columns), and B has dimensions p x q (p rows and q columns). For matrix multiplication to be possible, the number of columns in A (n) must be equal to the number of rows in B (p). The resulting matrix, C, will have dimensions m x q (m rows and q columns).

Here is the formula for matrix multiplication using the dot product:

C[i][j] = Σ (A[i][k] * B[k][j]) for k = 0 to n-1

where i ranges from 0 to m-1 and j ranges from 0 to q-1.

In other words, each element in the resulting matrix C is the dot product of the i-th row of matrix A and the j-th column of matrix B.

Let's see an example with two 3x3 matrices:

```
A = | a b c | B = | p q r |
| d e f | | s t u |
| g h i | | v w x |
C = | (a*p + b*s + c*v) (a*q + b*t + c*w) (a*r + b*u + c*x) |
| (d*p + e*s + f*v) (d*q + e*t + f*w) (d*r + e*u + f*x) |
| (g*p + h*s + i*v) (g*q + h*t + i*w) (g*r + h*u + i*x) |
```

The `Operator *()`

method can be used to perform matrix multiplication using the dot product.

### Vector Multiplication

Matrix-vector multiplication is a fundamental operation in linear algebra, computer graphics, and many other fields. This operation is used to apply transformations, such as scaling, rotation, and translation, to points and vectors in 2D and 3D space. In this section, we will discuss how to multiply a matrix by a vector and how this operation can be applied to 2D and 3D vectors in BlitzMax.

#### SVec2D, SVec2F, SVec2I )

2D Vectors (To multiply a 2x2 matrix by a 2D vector, perform the following steps:

- Multiply each element of the first row of the matrix by the corresponding element of the vector.
- Sum the results from step 1 to obtain the first element of the resulting vector.
- Multiply each element of the second row of the matrix by the corresponding element of the vector.
- Sum the results from step 3 to obtain the second element of the resulting vector.

Mathematically, this can be represented as:

```
| a c | | x | | a * x + c * y |
| b d | | y | = | b * x + d * y |
```

#### SVec3D, SVec3F, SVec3I )

3D Vectors (To multiply a 3x3 matrix by a 3D vector, follow these steps:

- Multiply each element of the first row of the matrix by the corresponding element of the vector.
- Sum the results from step 1 to obtain the first element of the resulting vector.
- Multiply each element of the second row of the matrix by the corresponding element of the vector.
- Sum the results from step 3 to obtain the second element of the resulting vector.
- Multiply each element of the third row of the matrix by the corresponding element of the vector.
- Sum the results from step 5 to obtain the third element of the resulting vector.

Mathematically, this can be represented as:

```
| a d g | | x | | a * x + d * y + g * z |
| b e h | | y | = | b * x + e * y + h * z |
| c f i | | z | | c * x + f * y + i * z |
```

You can use the `Apply()`

method to multiply a matrix by a vector.

Here's an example:

```
Local mat2D:SMat2D = SMat2D.Identity()
Local vec2D:SVec2D = New SVec2D(2, 3)
Local result2D:SVec2D = mat2D.Apply(vec2D)
Local mat3D:SMat3D = SMat3D.Identity()
Local vec3D:SVec3D = New SVec3D(2, 3, 4)
Local result3D:SVec3D = mat3D.Apply(vec3D)
```

## The Identity Matrix

The identity matrix is a special square matrix that has ones on the diagonal and zeros elsewhere. In mathematical notation, an identity matrix of size n x n is denoted as Iₙ. Here's an example of a 3x3 identity matrix:

```
I₃ = | 1 0 0 |
| 0 1 0 |
| 0 0 1 |
```

The identity matrix plays a crucial role in matrix algebra, as it serves as the "neutral element" for matrix multiplication. When you multiply any matrix by the identity matrix, the result is the original matrix unchanged. Mathematically, this property can be written as:

A * Iₙ = A

Iₙ * A = A

where A is any n x n matrix.

This property is analogous to the number 1 in scalar multiplication. Just as multiplying any number by 1 leaves the number unchanged (e.g., 7 * 1 = 7), multiplying any matrix by the identity matrix leaves the matrix unchanged.

The identity matrix is also important for other matrix operations. For example, when calculating the inverse of a matrix, the goal is to find a matrix B such that A * B = Iₙ. When this condition is met, matrix B is the inverse of matrix A.

The `Identity()`

method allows you create an identity matrix.

## Linear Transformations

Matrices are often used to represent linear transformations in various fields, including computer graphics and linear algebra. A linear transformation is a function that maps vectors from one vector space to another while preserving the operations of vector addition and scalar multiplication. In this section, we will discuss some of the key properties of linear transformations and how matrices can be used to represent them.

### Linearity

A linear transformation, T, has the property of linearity, which means it satisfies the following conditions:

- T(u + v) = T(u) + T(v) for all vectors u and v.
- T(c * u) = c * T(u) for all vectors u and any scalar c.

This property ensures that the transformation maintains the structure of the vector space, preserving parallelism and proportions between the vectors.

### Invertibility

A linear transformation is invertible if there exists another transformation, called its inverse, that can undo the effect of the original transformation. In terms of matrices, a matrix A is invertible if there exists a matrix B such that AB = BA = I, where I is the identity matrix. Invertible transformations are essential in many applications, as they allow us to reverse the effects of a transformation and recover the original data.

### Effect on Geometry

Linear transformations can have various effects on the geometry of shapes, including:

- Scaling: A transformation that changes the size of a shape, either uniformly or non-uniformly along different axes.
- Rotation: A transformation that rotates a shape around a specified point or axis.
- Shearing: A transformation that distorts a shape by shifting its points along one axis relative to the other axis.

## Orthogonal and Orthonormal Matrices

Orthogonal and orthonormal matrices are special types of square matrices that have unique properties, making them particularly useful in various applications such as computer graphics, physics, and linear algebra.

### Orthogonal Matrices

A matrix A is called an orthogonal matrix if its transpose, A^T, is also its inverse, i.e., A^T * A = A * A^T = I, where I is the identity matrix. In other words, the columns (and rows) of an orthogonal matrix are orthogonal to each other, meaning they form a 90-degree angle and their dot product is zero.

The geometric interpretation of orthogonal matrices is that they represent transformations that preserve lengths and angles, such as rotations and reflections.

### Orthonormal Matrices

An orthonormal matrix is an orthogonal matrix where the columns (and rows) are not only orthogonal but also have unit length (i.e., they are normalized). Orthonormal matrices simplify calculations in various applications, as they do not change the length of the vectors they transform.

### Applications

Orthogonal and orthonormal matrices play a significant role in computer graphics, as they are used to represent transformations that maintain the geometry of 3D objects. For instance, they can be employed to create rotation matrices, which are essential for rotating objects in 3D space.

Here's a BlitzMax example demonstrating the use of an orthonormal matrix to represent a 3D rotation:

```
Local angleX:Float = 30 ' in degrees
Local angleY:Float = 45 ' in degrees
Local angleZ:Float = 60 ' in degrees
' Create orthonormal rotation matrices for each axis
Local rotationMatrixX:SMat3D = SMat3D.RotationX(angleX)
Local rotationMatrixY:SMat3D = SMat3D.RotationY(angleY)
Local rotationMatrixZ:SMat3D = SMat3D.RotationZ(angleZ)
' Combine the rotations
Local rotationMatrix:SMat3D = rotationMatrixX * rotationMatrixY * rotationMatrixZ
' Apply the rotation to a 3D vector
Local vec:SVec3D = New SVec3D(1, 2, 3)
Local rotatedVec:SVec3D = rotationMatrix.Apply(vec)
```

When the rotation matrix is applied to a 3D vector, it will rotate the vector according to the specified angles. The order in which the rotations are combined (in this example, X, then Y, then Z) will determine the final rotation.

## Structs

Struct | Description |
---|---|

SMat2D | A 2x2 Matrix |

SMat3D | A 3x3 matrix. |

SMat4D | A standard 4x4 transformation matrix. |

SMat2F | A Float backed 2x2 Matrix. |

SMat3F | A Float backed 3x3 matrix. |

SMat4F | A standard Float backed 4x4 transformation matrix. |

SMat2I | An Int backed 2x2 Matrix. |

SMat3I | An Int backed 3x3 matrix. |

SMat4I | A standard Int backed 4x4 transformation matrix. |