pyvista.Transform

Contents

pyvista.Transform#

class Transform(
trans: TransformLike | Sequence[TransformLike] | None = None,
*,
point: VectorLike[float] | None = None,
multiply_mode: Literal['pre', 'post'] = 'post',
)[source]#

Describes linear transformations via a 4x4 matrix.

A Transform can be used to describe the full range of linear (also known as affine) coordinate transformations in three dimensions, which are internally represented as a 4x4 homogeneous transformation matrix.

The transformation methods (e.g. translate(), rotate(), concatenate()) can operate in either pre_multiply() or post_multiply() mode. In pre-multiply mode, any additional transformations will occur before any transformations represented by the current matrix. In post-multiply mode (the default), the additional transformation will occur after any transformations represented by the current matrix.

Note

This class performs all of its operations in a right-handed coordinate system with right-handed rotations. Some other graphics libraries use left-handed coordinate systems and rotations.

Added in version 0.45.

Parameters:
transTransformLike, optional

Initialize the transform with a transformation. By default, the transform is initialized as the identity matrix.

pointVectorLike[float], optional

Point to use when concatenating some transformations such as scale, rotation, etc. If set, two additional transformations are concatenated and added to the matrix_list:

By default, this value is None, which means that the scale, rotation, etc. transformations are performed about the origin (0, 0, 0).

multiply_mode‘pre’ | ‘post’, optional

Multiplication mode to use when concatenating. Set this to 'pre' for pre-multiplication or 'post' for post-multiplication.

See also

pyvista.DataSetFilters.transform()

Apply a transformation to a mesh.

Examples

Create a transformation and use + to concatenate a translation.

>>> import numpy as np
>>> import pyvista as pv
>>> position = (-0.6, -0.8, 2.1)
>>> translation_T = pv.Transform() + position
>>> translation_T.matrix
array([[ 1. ,  0. ,  0. , -0.6],
       [ 0. ,  1. ,  0. , -0.8],
       [ 0. ,  0. ,  1. ,  2.1],
       [ 0. ,  0. ,  0. ,  1. ]])

Using + performs the same concatenation as calling translate().

>>> np.array_equal(
...     translation_T.matrix, pv.Transform().translate(position).matrix
... )
True

Create a transformation and use * to concatenate a scaling matrix.

>>> scale_factor = 2.0
>>> scaling_T = pv.Transform() * scale_factor
>>> scaling_T.matrix
array([[2., 0., 0., 0.],
       [0., 2., 0., 0.],
       [0., 0., 2., 0.],
       [0., 0., 0., 1.]])

Using * performs the same concatenation as calling scale().

>>> np.array_equal(
...     scaling_T.matrix, pv.Transform().scale(scale_factor).matrix
... )
True

Concatenate the two transformations using addition. This will concatenate with post-multiplication such that the transformations are applied in order from left to right, i.e. translate first, then scale.

>>> transform_post = translation_T + scaling_T
>>> transform_post.matrix
array([[ 2. ,  0. ,  0. , -1.2],
       [ 0. ,  2. ,  0. , -1.6],
       [ 0. ,  0. ,  2. ,  4.2],
       [ 0. ,  0. ,  0. ,  1. ]])

Post-multiplication is equivalent to using matrix multiplication on the arrays directly but with the arguments reversed:

>>> mat_mul = scaling_T.matrix @ translation_T.matrix
>>> np.array_equal(transform_post.matrix, mat_mul)
True

Alternatively, concatenate the transformations by chaining the methods with a single Transform instance. Note that post-multiply is used by default.

>>> transform_post = pv.Transform()
>>> transform_post.multiply_mode
'post'
>>> _ = transform_post.translate(position).scale(scale_factor)
>>> transform_post.matrix
array([[ 2. ,  0. ,  0. , -1.2],
       [ 0. ,  2. ,  0. , -1.6],
       [ 0. ,  0. ,  2. ,  4.2],
       [ 0. ,  0. ,  0. ,  1. ]])

Use n_transformations to check that there are two transformations.

>>> transform_post.n_transformations
2

Use matrix_list to get a list of the transformations. Since post-multiplication is used, the translation matrix is first in the list since it was applied first, and the scale matrix is second.

>>> transform_post.matrix_list[0]  # translation
array([[ 1. ,  0. ,  0. , -0.6],
       [ 0. ,  1. ,  0. , -0.8],
       [ 0. ,  0. ,  1. ,  2.1],
       [ 0. ,  0. ,  0. ,  1. ]])
>>> transform_post.matrix_list[1]  # scaling
array([[2., 0., 0., 0.],
       [0., 2., 0., 0.],
       [0., 0., 2., 0.],
       [0., 0., 0., 1.]])

Create a similar transform but use pre-multiplication this time. Concatenate the transformations in the same order as before using translate() and scale().

>>> transform_pre = pv.Transform().pre_multiply()
>>> _ = transform_pre.translate(position).scale(scale_factor)

Alternatively, create the transform using matrix multiplication. Matrix multiplication concatenates the transformations using pre-multiply semantics such that the transformations are applied in order from right to left, i.e. scale first, then translate.

>>> transform_pre = translation_T @ scaling_T
>>> transform_pre.matrix
array([[ 2. ,  0. ,  0. , -0.6],
       [ 0. ,  2. ,  0. , -0.8],
       [ 0. ,  0. ,  2. ,  2.1],
       [ 0. ,  0. ,  0. ,  1. ]])

This is equivalent to using matrix multiplication directly on the arrays:

>>> mat_mul = translation_T.matrix @ scaling_T.matrix
>>> np.array_equal(transform_pre.matrix, mat_mul)
True

Show the matrix list again. Note how the order with pre-multiplication is the reverse of post-multiplication.

>>> transform_pre.matrix_list[0]  # scaling
array([[2., 0., 0., 0.],
       [0., 2., 0., 0.],
       [0., 0., 2., 0.],
       [0., 0., 0., 1.]])
>>> transform_pre.matrix_list[1]  # translation
array([[ 1. ,  0. ,  0. , -0.6],
       [ 0. ,  1. ,  0. , -0.8],
       [ 0. ,  0. ,  1. ,  2.1],
       [ 0. ,  0. ,  0. ,  1. ]])

Apply the two post- and pre-multiplied transformations to a dataset and plot them. Note how the meshes have different positions since post- and pre-multiplication produce different transformations.

>>> mesh_post = pv.Sphere().transform(transform_post)
>>> mesh_pre = pv.Cone().transform(transform_pre)
>>> pl = pv.Plotter()
>>> _ = pl.add_mesh(mesh_post, color='goldenrod')
>>> _ = pl.add_mesh(mesh_pre, color='teal')
>>> _ = pl.add_axes_at_origin()
>>> pl.show()
../../../_images/pyvista-Transform-1_00_00.png

Get the concatenated inverse transformation matrix of the pre-multiplication case.

>>> inverse_matrix = transform_pre.inverse_matrix
>>> inverse_matrix
array([[ 0.5 ,  0.  ,  0.  ,  0.3 ],
       [ 0.  ,  0.5 ,  0.  ,  0.4 ],
       [ 0.  ,  0.  ,  0.5 , -1.05],
       [ 0.  ,  0.  ,  0.  ,  1.  ]])

Similar to using matrix_list, we can inspect the individual transformation inverses with inverse_matrix_list.

>>> transform_pre.inverse_matrix_list[0]  # inverse scaling
array([[0.5, 0. , 0. , 0. ],
       [0. , 0.5, 0. , 0. ],
       [0. , 0. , 0.5, 0. ],
       [0. , 0. , 0. , 1. ]])
>>> transform_pre.inverse_matrix_list[1]  # inverse translation
array([[ 1. ,  0. ,  0. ,  0.6],
       [ 0. ,  1. ,  0. ,  0.8],
       [ 0. ,  0. ,  1. , -2.1],
       [ 0. ,  0. ,  0. ,  1. ]])

Transform the mesh by its inverse to restore it to its original un-scaled state and positioning at the origin.

>>> mesh_pre_inverted = mesh_pre.transform(inverse_matrix)
>>> pl = pv.Plotter()
>>> _ = pl.add_mesh(mesh_pre_inverted, color='teal')
>>> _ = pl.add_axes_at_origin()
>>> pl.show()
../../../_images/pyvista-Transform-1_01_00.png

Methods

Transform.apply(obj, /, *[, inverse, copy, ...])

Apply the current transformation matrix to points or a dataset.

Transform.concatenate(transform, *[, ...])

Concatenate a transformation matrix.

Transform.copy()

Return a deep copy of the transform.

Transform.decompose(*[, homogeneous])

Decompose the current transformation into its components.

Transform.flip_x(*[, point, multiply_mode])

Concatenate a reflection about the x-axis.

Transform.flip_y(*[, point, multiply_mode])

Concatenate a reflection about the y-axis.

Transform.flip_z(*[, point, multiply_mode])

Concatenate a reflection about the z-axis.

Transform.identity()

Set the transformation to the identity transformation.

Transform.invert()

Invert the current transformation.

Transform.post_multiply()

Set the multiplication mode to post-multiply.

Transform.pre_multiply()

Set the multiplication mode to pre-multiply.

Transform.reflect(*normal[, point, ...])

Concatenate a reflection matrix.

Transform.rotate(rotation, *[, point, ...])

Concatenate a rotation matrix.

Transform.rotate_vector(vector, angle, *[, ...])

Concatenate a rotation about a vector.

Transform.rotate_x(angle, *[, point, ...])

Concatenate a rotation about the x-axis.

Transform.rotate_y(angle, *[, point, ...])

Concatenate a rotation about the y-axis.

Transform.rotate_z(angle, *[, point, ...])

Concatenate a rotation about the z-axis.

Transform.scale(*factor[, point, multiply_mode])

Concatenate a scale matrix.

Transform.translate(*vector[, multiply_mode])

Concatenate a translation matrix.

Attributes

Transform.check_finite

Check that the matrix and inverse_matrix have finite values.

Transform.inverse_matrix

Return the inverse of the current transformation matrix.

Transform.inverse_matrix_list

Return a list of all inverse transformations applied by this Transform.

Transform.is_inverted

Get the inverse flag of the transformation.

Transform.matrix

Return or set the current transformation matrix.

Transform.matrix_list

Return a list of all current transformation matrices.

Transform.multiply_mode

Set or get the multiplication mode.

Transform.n_transformations

Return the current number of concatenated transformations.

Transform.point

Point to use when concatenating some transformations such as scale, rotation, etc.