1.2.2. Affine Matricies

class raysect.core.math.affinematrix.AffineMatrix3D

A 4x4 affine matrix.

These matrices are used for transforming between coordinate systems. Every primitive in Raysect works in its own local coordinate system, so it is common to need to transform 3D points from local to world spave and vice versa. Even though the vectors themselves are 3D, a 4x4 matrix is needed to completely specify a transformation from one 3D space to another.

The coordinate transformation is applied by multiplying the column vector for the desired Point3D/Vector3D against the transformation matrix. For example, if the original vector \(\vec{V_a}\) is in space A and the transformation matrix \(\mathbf{T_{AB}}\) describes the position and orientation of Space A relative to Space B, then the multiplication

\[\vec{V_{b}} = \mathbf{T_{AB}} \times \vec{V_a}\]

yields the same vector transformed into coordinate Space B, \(\vec{V_b}\).

The individual terms of the transformation matrix can be visualised in terms of the way they change the underlying basis vectors.

\[\begin{split}\mathbf{T_{AB}} = \left( \begin{array}{cccc} \vec{x_b}.x & \vec{y_b}.x & \vec{z_b}.x & \vec{t}.x \\ \vec{x_b}.y & \vec{y_b}.y & \vec{z_b}.y & \vec{t}.y \\ \vec{x_b}.z & \vec{y_b}.z & \vec{z_b}.z & \vec{t}.z \\ 0 & 0 & 0 & 1 \end{array} \right)\end{split}\]

Here the unit x-axis vector in space A, \(\vec{x}_a = (1, 0, 0)\), has been transformed into space B, \(\vec{x_b}\). The same applies to \(\vec{y_b}\) and \(\vec{z_b}\) for the \(\vec{y}_a\) and \(\vec{z}_a\) unit vectors respectively. Together the new basis vectors describe a rotation of the original coordinate system.

The vector \(\vec{t}\) in the last column corresponds to a translation vector between the origin’s of space A and space B.

Strictly speaking, the new rotation vectors don’t have to be normalised which corresponds to a scaling in addition to the rotation. For example, a scaling matrix would look like the following.

\[\begin{split}\mathbf{T_{scale}} = \left( \begin{array}{cccc} \vec{s}.x & 0 & 0 & 0 \\ 0 & \vec{s}.y & & 0 \\ 0 & 0 & \vec{s}.z & 0 \\ 0 & 0 & 0 & 1 \end{array} \right)\end{split}\]

Multiple transformations can be chained together by multiplying the matrices together, the resulting matrix will encode the full transformation. The order in which transformations are applied is very important. The operation \(\mathbf{M_{translate}} \times \mathbf{M_{rotate}}\) is different to \(\mathbf{M_{rotate}} \times \mathbf{M_{translate}}\) because matrices don’t commute, and physically these are different operations.

Warning

Because we are using column vectors, transformations should be applied right to left.

An an example operation, let us consider the case of moving and rotating a camera in our scene. Suppose we want to rotate our camera at an angle of \(\theta_x=45\) around the x-axis and translate the camera to position \(p=(0, 0, 3.5)\). This set of operations would be equivalent to:

\[\mathbf{T} = \mathbf{T_{translate}} \times \mathbf{T_{rotate}}\]

In code this would be equivalent to:

>>> transform = translate(0, 0, -3.5) * rotate_x(45)

If no initial values are passed to the matrix, it defaults to an identity matrix.

Parameters

m (object) – Any 4 x 4 indexable or 16 element object can be used to initialise the matrix. 16 element objects must be specified in row-major format.

__getitem__()

Indexing get operator.

Expects a tuple (row, column) as the index.

e.g. v = matrix[1, 2]

__mul__()

Multiplication operator.

>>> from raysect.core import translate, rotate_x
>>> translate(0, 0, -3.5) * rotate_x(45)
AffineMatrix3D([[1.0, 0.0, 0.0, 0.0],
                [0.0, 0.7071067811865476, -0.7071067811865475, 0.0],
                [0.0, 0.7071067811865475, 0.7071067811865476, -3.5],
                [0.0, 0.0, 0.0, 1.0]])
__setitem__()

Indexing set operator.

Expects a tuple (row, column) as the index.

e.g. matrix[1, 2] = 7.0

inverse()

Calculates the inverse of the affine matrix.

Returns an AffineMatrix3D containing the inverse.

Raises a ValueError if the matrix is singular and the inverse can not be calculated. All valid affine transforms should be invertable.

>>> from raysect.core import AffineMatrix3D
>>> m = AffineMatrix3D([[0.0, 0.0, 1.0, 0.0],
                        [1.0, 0.0, 0.0, 0.0],
                        [0.0, 1.0, 0.0, 0.0],
                        [0.0, 0.0, 0.0, 1.0]])
>>> m.inverse()
AffineMatrix3D([[0.0, 1.0, 0.0, -0.0],
                [0.0, 0.0, 1.0, 0.0],
                [1.0, 0.0, 0.0, -0.0],
                [0.0, 0.0, -0.0, 1.0]])
is_close()

Is this matrix equal to another matrix within a numerical tolerance.

The method has a default tolerance of 1e-8 to account for errors that may have accumulated due to numerical accuracy limits. The tolerance may be altered by setting the tolerance argument.

Parameters
  • other – The other matrix.

  • tolerance – Numerical tolerance (default: 1e-8)

Returns

True/False

is_identity()

Identifies if the matrix is an identity matrix.

Returns True if the matrix is an identify matrix, False otherwise.

The method has a default tolerance of 1e-8 to account for errors due to numerical accuracy limits. The tolerance may be altered by setting the tolerance argument.

Parameters

tolerance – Numerical tolerance (default: 1e-8)

Returns

True/False

raysect.core.math.transform.translate()

Returns an affine matrix representing a translation of the coordinate space.

Equivalent to the transform matrix, \(\mathbf{T_{AB}}\), where \(\vec{t}\) is the vector from the origin of space A to space B.

\[\begin{split}\mathbf{T_{AB}} = \left( \begin{array}{cccc} 1 & 0 & 0 & \vec{t}.x \\ 0 & 1 & 0 & \vec{t}.y \\ 0 & 0 & 1 & \vec{t}.z \\ 0 & 0 & 0 & 1 \end{array} \right)\end{split}\]
Parameters
  • x (float) – x-coordinate

  • y (float) – y-coordinate

  • z (float) – z-coordinate

Return type

AffineMatrix3D

>>> from raysect.core import translate
>>> translate(0, 1, 2)
AffineMatrix3D([[1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 1.0],
                [0.0, 0.0, 1.0, 2.0],
                [0.0, 0.0, 0.0, 1.0]])
raysect.core.math.transform.rotate_x()

Returns an affine matrix representing the rotation of the coordinate space about the X axis by the supplied angle.

The rotation direction is clockwise when looking along the x-axis.

\[\begin{split}\mathbf{T_{AB}} = \left( \begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & \cos{\theta} & -\sin{\theta} & 0 \\ 0 & \sin{\theta} & \cos{\theta} & 0 \\ 0 & 0 & 0 & 1 \end{array} \right)\end{split}\]
Parameters

angle (float) – The angle \(\theta\) specified in degrees.

Return type

AffineMatrix3D

>>> from raysect.core import rotate_x
>>> rotate_x(45)
AffineMatrix3D([[1.0, 0.0, 0.0, 0.0],
                [0.0, 0.7071067811865476, -0.7071067811865475, 0.0],
                [0.0, 0.7071067811865475, 0.7071067811865476, 0.0],
                [0.0, 0.0, 0.0, 1.0]])
raysect.core.math.transform.rotate_y()

Returns an affine matrix representing the rotation of the coordinate space about the Y axis by the supplied angle.

The rotation direction is clockwise when looking along the y-axis.

\[\begin{split}\mathbf{T_{AB}} = \left( \begin{array}{cccc} \cos{\theta} & 0 & \sin{\theta} & 0 \\ 0 & 1 & 0 & 0 \\ -\sin{\theta} & 0 & \cos{\theta} & 0 \\ 0 & 0 & 0 & 1 \end{array} \right)\end{split}\]
Parameters

angle (float) – The angle \(\theta\) specified in degrees.

Return type

AffineMatrix3D

raysect.core.math.transform.rotate_z()

Returns an affine matrix representing the rotation of the coordinate space about the Z axis by the supplied angle.

The rotation direction is clockwise when looking along the z-axis.

\[\begin{split}\mathbf{T_{AB}} = \left( \begin{array}{cccc} \cos{\theta} & -\sin{\theta} & 0 & 0 \\ \sin{\theta} & \cos{\theta} & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array} \right)\end{split}\]
Parameters

angle (float) – The angle \(\theta\) specified in degrees.

Return type

AffineMatrix3D

raysect.core.math.transform.rotate()

Returns an affine transform matrix representing an intrinsic rotation with an axis order (-Y)(-X)’Z’’.

For an object aligned such that forward is the +ve Z-axis, left is the +ve X-axis and up is the +ve Y-axis then this rotation operation corresponds to the yaw, pitch and roll of the object.

Parameters
  • yaw (float) – Yaw angle in degrees.

  • pitch (float) – Pitch angle in degrees.

  • roll (float) – Roll angle in degrees.

Return type

AffineMatrix3D

raysect.core.math.transform.rotate_vector()

Returns an affine matrix representing the rotation of the coordinate space about the supplied vector by the specified angle.

Parameters
  • angle (float) – The angle specified in degrees.

  • v (Vector3D) – The vector about which to rotate.

Return type

AffineMatrix3D

>>> from raysect.core import rotate_vector
>>> rotate_vector(90, Vector3D(1, 0, 0))
AffineMatrix3D([[1.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, -1.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]])
raysect.core.math.transform.rotate_basis()

Returns a rotation matrix defined by forward and up vectors.

The +ve Z-axis of the resulting coordinate space will be aligned with the forward vector. The +ve Y-axis will be aligned to lie in the plane defined the forward and up vectors, along the projection of the up vector that lies orthogonal to the forward vector. The X-axis will lie perpendicular to the plane.

The forward and upwards vectors need not be orthogonal. The up vector will be rotated in the plane defined by the two vectors until it is orthogonal.

Parameters
  • forward (Vector3D) – A Vector3D object defining the forward direction.

  • up (Vector3D) – A Vector3D object defining the up direction.

Return type

AffineMatrix3D

>>> from raysect.core import rotate_basis, Vector3D
>>> rotate_basis(Vector3D(1, 0, 0), Vector3D(0, 0, 1))
AffineMatrix3D([[0.0, 0.0, 1.0, 0.0],
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 1.0]])