# Examples from pyvista.Transform
# ===============================

# Create a transformation and use `+` to compose 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

# Using `+` performs the same concatenation as calling `translate()`.
np.array_equal(
    translation_T.matrix, pv.Transform().translate(position).matrix
)

# Create a transformation and use `*` to compose a scaling matrix.
scale_factor = 2.0
scaling_T = pv.Transform() * scale_factor
scaling_T.matrix

# Using `*` performs the same concatenation as calling `scale()`.
np.array_equal(scaling_T.matrix, pv.Transform().scale(scale_factor).matrix)

# Compose the two transformations using `*`. This will compose 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

# 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)

# Alternatively, compose 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
_ = transform_post.translate(position).scale(scale_factor)
transform_post.matrix

# Use `n_transformations` to check that there are two transformations.
transform_post.n_transformations

# 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

transform_post.matrix_list[1]  # scaling

# Create a similar transform but use pre-multiplication this time. Compose 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)

# 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)

# Show the matrix list again. Note how the order with pre-multiplication is the
# reverse of post-multiplication.
transform_pre.matrix_list[0]  # scaling

transform_pre.matrix_list[1]  # translation

# 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, inplace=False)
mesh_pre = pv.Cone().transform(transform_pre, inplace=False)
pl = pv.Plotter()
_ = pl.add_mesh(mesh_post, color='goldenrod')
_ = pl.add_mesh(mesh_pre, color='teal')
_ = pl.add_axes_at_origin()
pl.show()

# Get the composed inverse transformation matrix of the pre-multiplication case.
inverse_matrix = transform_pre.inverse_matrix
inverse_matrix

# Similar to using `matrix_list`, we can inspect the individual transformation
# inverses with `inverse_matrix_list`.
transform_pre.inverse_matrix_list[0]  # inverse scaling

transform_pre.inverse_matrix_list[1]  # inverse translation

# 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, inplace=False)
pl = pv.Plotter()
_ = pl.add_mesh(mesh_pre_inverted, color='teal')
_ = pl.add_axes_at_origin()
pl.show()

# ----------------------------------------------------------------------
# Generated by sphinx-examples-as-code https://github.com/pyvista/sphinx-examples-as-code

