Source code for blenderproc.python.utility.MathUtility

import bpy
import numpy as np
from mathutils import Matrix, Vector, Euler
from typing import Union, List

[docs]def change_coordinate_frame_of_point(point: Union[np.ndarray, list, Vector], new_frame: List[str]) -> np.ndarray: """ Transforms the given point into another coordinate frame. Example: [1, 2, 3] and ["X", "-Z", "Y"] => [1, -3, 2] :param point: The point to convert in form of a np.ndarray, list or mathutils.Vector. :param new_frame: An array containing three elements, describing each axis of the new coordinate frame based on the axes of the current frame. (Allowed values: "X", "Y", "Z", "-X", "-Y", "-Z") :return: The converted point also in form of a np.ndarray """ assert len(new_frame) == 3, "The specified coordinate frame has more or less than tree axes: {}".format(new_frame) point = np.array(point) output = [] for i, axis in enumerate(new_frame): axis = axis.upper() if axis.endswith("X"): output.append(point[0]) elif axis.endswith("Y"): output.append(point[1]) elif axis.endswith("Z"): output.append(point[2]) else: raise Exception("Invalid axis: " + axis) if axis.startswith("-"): output[-1] *= -1 return np.array(output)
[docs]def change_target_coordinate_frame_of_transformation_matrix(matrix: Union[np.ndarray, Matrix], new_frame: list) -> np.ndarray: """ Changes the coordinate frame the given transformation matrix is mapping to. Given a matrix $T_A^B$ that maps from A to B, this function can be used to change the axes of B into B' and therefore end up with $T_A^B'$. :param matrix: The matrix to convert in form of a np.ndarray or mathutils.Matrix :param new_frame: An array containing three elements, describing each axis of the new coordinate frame based on the axes of the current frame. (Allowed values: "X", "Y", "Z", "-X", "-Y", "-Z") :return: The converted matrix is in form of a np.ndarray """ tmat = MathUtility._build_coordinate_frame_changing_transformation_matrix(new_frame) # Apply transformation matrix output = np.matmul(tmat, matrix) return output
[docs]def change_source_coordinate_frame_of_transformation_matrix(matrix: Union[np.ndarray, Matrix], new_frame: list) -> np.ndarray: """ Changes the coordinate frame the given transformation matrix is mapping from. Given a matrix $T_A^B$ that maps from A to B, this function can be used to change the axes of A into A' and therefore end up with $T_A'^B$. :param matrix: The matrix to convert in form of a np.ndarray or mathutils.Matrix :param new_frame: An array containing three elements, describing each axis of the new coordinate frame based on the axes of the current frame. (Allowed values: "X", "Y", "Z", "-X", "-Y", "-Z") :return: The converted matrix is in form of a np.ndarray """ tmat = MathUtility._build_coordinate_frame_changing_transformation_matrix(new_frame) tmat = np.linalg.inv(tmat) # Apply transformation matrix output = np.matmul(matrix, tmat) return output
[docs]def build_transformation_mat(translation: Union[np.ndarray, list, Vector], rotation: Union[np.ndarray, List[list], Matrix]) -> np.ndarray: """ Build a transformation matrix from translation and rotation parts. :param translation: A (3,) vector representing the translation part. :param rotation: A 3x3 rotation matrix or Euler angles of shape (3,). :return: The 4x4 transformation matrix. """ translation = np.array(translation) rotation = np.array(rotation) mat = np.eye(4) if translation.shape[0] == 3: mat[:3, 3] = translation else: raise Exception("translation has invalid shape: {}. Must be (3,) or (3,1) vector.".format(translation.shape)) if rotation.shape == (3,3): mat[:3,:3] = rotation elif rotation.shape[0] == 3: mat[:3,:3] = np.array(Euler(rotation).to_matrix()) else: raise Exception("rotation has invalid shape: {}. Must be rotation matrix of shape (3,3) or Euler angles of shape (3,) or (3,1).".format(rotation.shape)) return mat
[docs]class MathUtility:
[docs] @staticmethod def _build_coordinate_frame_changing_transformation_matrix(destination_frame: list) -> np.ndarray: """ Builds a transformation matrix that switches the coordinate frame. :param destination_frame: An array containing three elements, describing each axis of the destination coordinate frame based on the axes of the source frame. (Allowed values: "X", "Y", "Z", "-X", "-Y", "-Z") :return: The transformation matrix """ assert len(destination_frame) == 3, "The specified coordinate frame has more or less than tree axes: {}".format(destination_frame) # Build transformation matrix that maps the given matrix to the specified coordinate frame. tmat = np.zeros((4, 4)) for i, axis in enumerate(destination_frame): axis = axis.upper() if axis.endswith("X"): tmat[i, 0] = 1 elif axis.endswith("Y"): tmat[i, 1] = 1 elif axis.endswith("Z"): tmat[i, 2] = 1 else: raise Exception("Invalid axis: " + axis) if axis.startswith("-"): tmat[i] *= -1 tmat[3, 3] = 1 return tmat