np_matrix_to_euler, np_matrix_normalized

This commit is contained in:
Andrej730
2025-01-13 13:22:04 +05:00
parent 0ac9d739f8
commit a968b61d02
2 changed files with 41 additions and 0 deletions
@@ -90,6 +90,14 @@ def np_normalized(v: VectorType) -> np.ndarray:
return np.divide(v, np.linalg.norm(v))
def np_matrix_normalized(matrix: np.ndarray) -> np.ndarray:
# Ensure translation is not affected.
scale_factors = np.linalg.norm(matrix[:3, :3], axis=0)
rotation_matrix = matrix.copy()
rotation_matrix[:3, :3] /= scale_factors
return rotation_matrix
def np_lerp(a: VectorType, b: VectorType, t: float) -> np.ndarray:
return a + np.subtract(b, a) * t
@@ -178,6 +186,23 @@ def np_rotation_matrix(
return matrix
def np_matrix_to_euler(matrix: np.ndarray) -> tuple[float, float, float]:
"""Convert a rotation matrix to Euler angles.
Designed to work similar to `mathutils.Matrix.to_euler`.
Currently only XYZ rotation is supported.
"""
if matrix.shape not in ((3, 3), (4, 4)):
raise ValueError(f"Matrix must be 3x3 or 4x4, got {matrix.shape}.")
matrix = np_matrix_normalized(matrix)
y = -np.arcsin(matrix[2, 0])
cos_y = np.cos(y)
x = np.arctan2(matrix[2, 1] / cos_y, matrix[2, 2] / cos_y)
z = np.arctan2(matrix[1, 0] / cos_y, matrix[0, 0] / cos_y)
return (x, y, z)
def np_normal(vectors: SequenceOfVectors) -> np.ndarray:
"""Normal of 3D Polygon.
@@ -30,6 +30,7 @@ from ifcopenshell.util.shape_builder import (
np_angle_signed,
np_normal,
np_intersect_line_line,
np_matrix_to_euler,
)
from math import degrees, radians
from typing import Any, Union
@@ -57,6 +58,21 @@ class TestMathutilsCompatibleMethods(test.bootstrap.IFC4):
rotation_vector_args = radians(45), 4, Vector((1, 1, 1)).normalized()
assert np.allclose(Matrix.Rotation(*rotation_vector_args), np_rotation_matrix(*rotation_vector_args))
def test_np_matrix_to_euler(self):
from mathutils import Euler
# Test 3x3.
rot = Euler((0.5, 0.5, 0.5)).to_matrix()
assert np.allclose(rot.to_euler(), np_matrix_to_euler(V(rot)))
rot = rot.to_4x4()
assert np.allclose(rot.to_euler(), np_matrix_to_euler(V(rot)))
# Ensure support scaled matrices.
rot = Euler((0.5, 0.5, 0.5)).to_matrix()
rot.col[0] *= 2
assert np.allclose(rot.to_euler(), np_matrix_to_euler(V(rot)))
def test_np_angle(self):
from mathutils import Vector