Add rot_3D and tests for rot_2D/rot_3D

This commit is contained in:
washingtonta103380 committed 2026-10-20 21:06:16 +02:00
1 parent 833161651b
commit d065d4d17d
7 files changed
+102 -7

No files matched your search

-2
View File
@@ -1,2 +0,0 @@
print("APOLLO")
print("hallo")
View File
Whitespace-only changes.
+10 -1
View File
@@ -2,4 +2,13 @@
name = "matrixmania"
version = "0.1.0"
dependencies = ["tabulate", "ruff"]
dependencies = ["tabulate", "ruff"]
[project.optional-dependencies]
dev = ["pytest", "ruff", "pytest-cov"]
[tool.pytest.ini_options]
pythonpath = "src"
testpaths = "test"
View File
Whitespace-only changes.
+34 -4
View File
@@ -1,5 +1,5 @@
import math
from tabulate import tabulate
def matmul(matrix_a: list[list[float | int]], matrix_b: list[list[float | int]]) -> list[list[float | int]]:
"""Multipliziert zwei Matrizen, die als verschachtelte Listen dargestellt sind.
@@ -91,6 +91,37 @@ def rot_2D(theta: float) -> list[list[float]]:
[sin_theta, cos_theta]
]
def rot_3D(angle: float, axis: str) -> list[list[float]]:
"""Gibt die 3D-Rotationsmatrix um eine Koordinatenachse zurück.
Formeln (θ = angle, im Bogenmaß):
R_x(θ) = [[1, 0, 0], [0, cos θ, -sin θ], [0, sin θ, cos θ]]
R_y(θ) = [[cos θ, 0, sin θ], [0, 1, 0], [-sin θ, 0, cos θ]]
R_z(θ) = [[cos θ, -sin θ, 0], [sin θ, cos θ, 0], [0, 0, 1]]
Args:
angle: Der Rotationswinkel in Bogenmaß (Radians).
axis: Die Rotationsachse: "x", "y" oder "z".
Returns:
Die 3x3-Rotationsmatrix als 2D-Liste.
Raises:
ValueError: Wenn axis nicht "x", "y" oder "z" ist.
"""
c = math.cos(angle)
s = math.sin(angle)
if axis == "x":
return [[1.0, 0.0, 0.0], [0.0, c, -s], [0.0, s, c]]
if axis == "y":
return [[c, 0.0, s], [0.0, 1.0, 0.0], [-s, 0.0, c]]
if axis == "z":
return [[c, -s, 0.0], [s, c, 0.0], [0.0, 0.0, 1.0]]
raise ValueError(f"Ungültige Achse '{axis}': erlaubt sind 'x', 'y' oder 'z'.")
if __name__ == "__main__":
@@ -154,8 +185,7 @@ if __name__ == "__main__":
theta = math.pi / 2 #1,57...
print(f"Winkel: {math.degrees(theta)} Grad (pi / 2)")
print(rot_2D(theta))
print(tabulate(rot_2D(1.0)))
print(rot_2D(1.0))
print("hallo")
print("apollo")
View File
Whitespace-only changes.
+58
View File
@@ -0,0 +1,58 @@
import math
import pytest
from matrixmania.compute import matmul, rot_2D, rot_3D, transpose
def assert_matrix_close(actual, expected):
"""Vergleicht zwei Matrizen elementweise mit Toleranz."""
assert len(actual) == len(expected)
for row_a, row_e in zip(actual, expected):
assert row_a == pytest.approx(row_e, abs=1e-9)
# ---------- rot_2D ----------
def test_rot_2D_zero():
assert_matrix_close(rot_2D(0), [[1, 0], [0, 1]])
def test_rot_2D_90_degree():
assert_matrix_close(rot_2D(math.pi / 2), [[0, -1], [1, 0]])
def test_rot_2D_invalid_input():
with pytest.raises(TypeError):
rot_2D("abc")
# ---------- rot_3D ----------
@pytest.mark.parametrize("axis", ["x", "y", "z"])
def test_rot_3D_zero_is_identity(axis):
assert_matrix_close(rot_3D(0, axis), [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
@pytest.mark.parametrize(
"axis, expected",
[
("x", [[1, 0, 0], [0, 0, -1], [0, 1, 0]]),
("y", [[0, 0, 1], [0, 1, 0], [-1, 0, 0]]),
("z", [[0, -1, 0], [1, 0, 0], [0, 0, 1]]),
],
)
def test_rot_3D_90_degree(axis, expected):
assert_matrix_close(rot_3D(math.pi / 2, axis), expected)
@pytest.mark.parametrize("axis", ["x", "y", "z"])
def test_rot_3D_is_orthogonal(axis):
r = rot_3D(1.0, axis)
assert_matrix_close(matmul(r, transpose(r)), [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
@pytest.mark.parametrize("axis", ["w", "X", "", "xy"])
def test_rot_3D_invalid_axis(axis):
with pytest.raises(ValueError):
rot_3D(1.0, axis)