Aufgabe rot_3D

This commit is contained in:
kuehnleinma103760 committed 2026-10-22 16:53:53 +02:00
1 parent c9fabdf896
commit 3f7c8b1195
4 files changed
+453 -8

No files matched your search

+5 -1
View File
@@ -1 +1,5 @@
from .compute import matmul, transpose, rot_2d
"""MatrixMania - Paket für Matrixoperationen."""
from .compute import matmul, rot_2d, rot_3d, transpose
__all__ = ["matmul", "rot_2d", "rot_3d", "transpose"]
+96 -7
View File
@@ -5,7 +5,9 @@ import math
from tabulate import tabulate
def matmul(matrix_a: list[list[float]], matrix_b: list[list[float]]) -> list[list[float]]:
def matmul(
matrix_a: list[list[float]], matrix_b: list[list[float]]
) -> list[list[float]]:
"""Berechnet das Matrixprodukt zweier Matrizen (matrix_a @ matrix_b).
:param matrix_a: Die linke Matrix.
@@ -21,11 +23,15 @@ def matmul(matrix_a: list[list[float]], matrix_b: list[list[float]]) -> list[lis
rows_a, cols_a = len(matrix_a), len(matrix_a[0])
rows_b, cols_b = len(matrix_b), len(matrix_b[0])
if any(len(row) != cols_a for row in matrix_a) or any(len(row) != cols_b for row in matrix_b):
if any(len(row) != cols_a for row in matrix_a) or any(
len(row) != cols_b for row in matrix_b
):
raise ValueError("Alle Zeilen einer Matrix müssen dieselbe Länge besitzen.")
if cols_a != rows_b:
raise ValueError("Matrixdimensionen stimmen für die Multiplikation nicht überein.")
raise ValueError(
"Matrixdimensionen stimmen für die Multiplikation nicht überein."
)
result: list[list[float]] = []
for i in range(rows_a):
@@ -78,10 +84,56 @@ def rot_2d(angle: float) -> list[list[float]]:
def rot_3d(angle: float, axis: str) -> list[list[float]]:
pass
"""Berechnet die 3D-Rotationsmatrix für einen Drehwinkel um eine Achse.
Die Rotationsmatrizen lauten:
- Für die x-Achse R_x(theta):
[[1, 0, 0],
[0, cos(theta), -sin(theta)],
[0, sin(theta), cos(theta)]]
- Für die y-Achse R_y(theta):
[[cos(theta), 0, sin(theta)],
[0, 1, 0],
[-sin(theta), 0, cos(theta)]]
- Für die z-Achse R_z(theta):
[[cos(theta), -sin(theta), 0],
[sin(theta), cos(theta), 0],
[0, 0, 1]]
:param angle: Der Rotationswinkel im Bogenmaß (Radiant).
:param axis: Die Rotationsachse ('x', 'y' oder 'z').
:return: Die 3x3-Rotationsmatrix als verschachtelte Liste.
:raises ValueError: Wenn die Achse nicht 'x', 'y' oder 'z' ist.
"""
if axis not in ("x", "y", "z"):
raise ValueError(
f"Ungültige Achse '{axis}'. Erlaubte Werte sind 'x', 'y' oder 'z'."
)
cos_theta = math.cos(angle)
sin_theta = math.sin(angle)
if axis == "x":
return [
[1.0, 0.0, 0.0],
[0.0, cos_theta, -sin_theta],
[0.0, sin_theta, cos_theta],
]
if axis == "y":
return [
[cos_theta, 0.0, sin_theta],
[0.0, 1.0, 0.0],
[-sin_theta, 0.0, cos_theta],
]
return [
[cos_theta, -sin_theta, 0.0],
[sin_theta, cos_theta, 0.0],
[0.0, 0.0, 1.0],
]
def test_functions():
def test_functions() -> None:
"""Testet die mathematischen Hilfsfunktionen für Matrixoperationen."""
a1 = [
[3, 4, -1, 4],
[-2, 2, 5, 1],
@@ -97,7 +149,9 @@ def test_functions():
[-1, 27, -8],
]
c1 = matmul(a1, b1)
assert c1 == expected_c1, f"Fehler in Beispiel 1: Erwartet {expected_c1}, erhalten {c1}"
assert c1 == expected_c1, (
f"Fehler in Beispiel 1: Erwartet {expected_c1}, erhalten {c1}"
)
print("Test 1 (Skript-Beispiel) erfolgreich bestanden!")
a2 = [
@@ -178,5 +232,40 @@ def test_functions():
assert math.isclose(rotated_point[1][0], 1.0, abs_tol=1e-9)
print("Test rot_2D (Vektordrehung mit matmul) erfolgreich bestanden!")
# Test 10: rot_3d um x-Achse um pi / 2
rot_x_90 = rot_3d(math.pi / 2, "x")
v_y = [[0.0], [1.0], [0.0]]
rotated_v_y = matmul(rot_x_90, v_y)
assert math.isclose(rotated_v_y[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated_v_y[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated_v_y[2][0], 1.0, abs_tol=1e-9)
print("Test rot_3D (x-Achse) erfolgreich bestanden!")
# Test 11: rot_3d um y-Achse um pi / 2
rot_y_90 = rot_3d(math.pi / 2, "y")
v_z = [[0.0], [0.0], [1.0]]
rotated_v_z = matmul(rot_y_90, v_z)
assert math.isclose(rotated_v_z[0][0], 1.0, abs_tol=1e-9)
assert math.isclose(rotated_v_z[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated_v_z[2][0], 0.0, abs_tol=1e-9)
print("Test rot_3D (y-Achse) erfolgreich bestanden!")
# Test 12: rot_3d um z-Achse um pi / 2
rot_z_90 = rot_3d(math.pi / 2, "z")
v_x = [[1.0], [0.0], [0.0]]
rotated_v_x = matmul(rot_z_90, v_x)
assert math.isclose(rotated_v_x[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated_v_x[1][0], 1.0, abs_tol=1e-9)
assert math.isclose(rotated_v_x[2][0], 0.0, abs_tol=1e-9)
print("Test rot_3D (z-Achse) erfolgreich bestanden!")
# Test 13: rot_3d mit ungültiger Achse
try:
rot_3d(math.pi / 2, "invalid")
raise AssertionError("Ungültige Achse wurde nicht abgefangen!")
except ValueError:
print("Test 13 (rot_3d ungültige Achse) erfolgreich abgefangen!")
if __name__ == "__main__":
print(tabulate(rot_2d(1.0)))
print(tabulate(rot_2d(1.0)))
+154
View File
@@ -0,0 +1,154 @@
"""Unit-Tests für die mathematischen Matrixfunktionen in compute.py."""
import math
import pytest
from matrixmania.compute import matmul, rot_2d, rot_3d, test_functions, transpose
def test_matmul_valid() -> None:
"""Testet die Matrixmultiplikation mit gültigen Matrizen."""
a = [
[3.0, 4.0, -1.0, 4.0],
[-2.0, 2.0, 5.0, 1.0],
]
b = [
[1.0, 3.0, -2.0],
[2.0, 5.0, 1.0],
[-1.0, 4.0, -4.0],
[2.0, 3.0, 6.0],
]
expected = [
[20.0, 37.0, 26.0],
[-1.0, 27.0, -8.0],
]
assert matmul(a, b) == expected
def test_matmul_invalid_dimensions() -> None:
"""Testet, dass bei inkompatiblen Matrixdimensionen ValueError geworfen wird."""
a = [[1.0, 2.0], [3.0, 4.0]]
b = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
with pytest.raises(ValueError):
matmul(a, b)
def test_matmul_empty_or_uneven() -> None:
"""Testet matmul mit leeren oder ungleichmäßigen Matrizen."""
with pytest.raises(ValueError):
matmul([], [[1.0]])
with pytest.raises(ValueError):
matmul([[1.0, 2.0], [3.0]], [[1.0], [2.0]])
def test_transpose_valid() -> None:
"""Testet das Transponieren einer regulären Matrix."""
matrix = [
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
]
expected = [
[1.0, 4.0],
[2.0, 5.0],
[3.0, 6.0],
]
assert transpose(matrix) == expected
def test_transpose_invalid() -> None:
"""Testet, dass transpose bei leeren oder unregelmäßigen Matrizen Fehler wirft."""
with pytest.raises(ValueError):
transpose([])
with pytest.raises(ValueError):
transpose([[1.0, 2.0], [3.0]])
def test_rot_2d() -> None:
"""Testet die 2D-Rotation für verschiedene Winkel."""
rot_0 = rot_2d(0.0)
assert math.isclose(rot_0[0][0], 1.0, abs_tol=1e-9)
assert math.isclose(rot_0[0][1], 0.0, abs_tol=1e-9)
assert math.isclose(rot_0[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(rot_0[1][1], 1.0, abs_tol=1e-9)
rot_90 = rot_2d(math.pi / 2)
assert math.isclose(rot_90[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(rot_90[0][1], -1.0, abs_tol=1e-9)
assert math.isclose(rot_90[1][0], 1.0, abs_tol=1e-9)
assert math.isclose(rot_90[1][1], 0.0, abs_tol=1e-9)
def test_rot_3d_x_axis() -> None:
"""Testet die 3D-Rotation um die x-Achse."""
matrix_x_0 = rot_3d(0.0, "x")
expected_identity = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
for r in range(3):
for c in range(3):
assert math.isclose(matrix_x_0[r][c], expected_identity[r][c], abs_tol=1e-9)
matrix_x_90 = rot_3d(math.pi / 2, "x")
v_y = [[0.0], [1.0], [0.0]]
rotated = matmul(matrix_x_90, v_y)
assert math.isclose(rotated[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated[2][0], 1.0, abs_tol=1e-9)
def test_rot_3d_y_axis() -> None:
"""Testet die 3D-Rotation um die y-Achse."""
matrix_y_0 = rot_3d(0.0, "y")
expected_identity = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
for r in range(3):
for c in range(3):
assert math.isclose(matrix_y_0[r][c], expected_identity[r][c], abs_tol=1e-9)
matrix_y_90 = rot_3d(math.pi / 2, "y")
v_z = [[0.0], [0.0], [1.0]]
rotated = matmul(matrix_y_90, v_z)
assert math.isclose(rotated[0][0], 1.0, abs_tol=1e-9)
assert math.isclose(rotated[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated[2][0], 0.0, abs_tol=1e-9)
def test_rot_3d_z_axis() -> None:
"""Testet die 3D-Rotation um die z-Achse."""
matrix_z_0 = rot_3d(0.0, "z")
expected_identity = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
for r in range(3):
for c in range(3):
assert math.isclose(matrix_z_0[r][c], expected_identity[r][c], abs_tol=1e-9)
matrix_z_90 = rot_3d(math.pi / 2, "z")
v_x = [[1.0], [0.0], [0.0]]
rotated = matmul(matrix_z_90, v_x)
assert math.isclose(rotated[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(rotated[1][0], 1.0, abs_tol=1e-9)
assert math.isclose(rotated[2][0], 0.0, abs_tol=1e-9)
def test_rot_3d_invalid_axis() -> None:
"""Testet, dass ungültige Achsen einen ValueError auslösen."""
with pytest.raises(ValueError, match="Ungültige Achse"):
rot_3d(1.0, "w")
with pytest.raises(ValueError):
rot_3d(0.5, "123")
with pytest.raises(ValueError):
rot_3d(0.0, "")
def test_test_functions_execution() -> None:
"""Testet die Ausführung der integrierten Testfunktion."""
test_functions()
+198
View File
@@ -0,0 +1,198 @@
"""Unit-Tests für die Rotationsfunktionen in compute.py."""
import math
import pytest
from matrixmania import rot_2d, rot_3d
def test_rot_2d_zero_angle() -> None:
"""Testet die 2D-Rotation um 0 Radiant (Einheitsmatrix)."""
# Arrange
angle = 0.0
# Act
result = rot_2d(angle)
# Assert
assert math.isclose(result[0][0], 1.0, abs_tol=1e-9)
assert math.isclose(result[0][1], 0.0, abs_tol=1e-9)
assert math.isclose(result[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(result[1][1], 1.0, abs_tol=1e-9)
def test_rot_2d_pi_half() -> None:
"""Testet die 2D-Rotation um pi / 2 Radiant (90 Grad)."""
# Arrange
angle = math.pi / 2
# Act
result = rot_2d(angle)
# Assert
assert math.isclose(result[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(result[0][1], -1.0, abs_tol=1e-9)
assert math.isclose(result[1][0], 1.0, abs_tol=1e-9)
assert math.isclose(result[1][1], 0.0, abs_tol=1e-9)
def test_rot_2d_pi() -> None:
"""Testet die 2D-Rotation um pi Radiant (180 Grad)."""
# Arrange
angle = math.pi
# Act
result = rot_2d(angle)
# Assert
assert math.isclose(result[0][0], -1.0, abs_tol=1e-9)
assert math.isclose(result[0][1], 0.0, abs_tol=1e-9)
assert math.isclose(result[1][0], 0.0, abs_tol=1e-9)
assert math.isclose(result[1][1], -1.0, abs_tol=1e-9)
def test_rot_2d_negative_angle() -> None:
"""Testet die 2D-Rotation mit einem negativen Winkel (-pi / 2)."""
# Arrange
angle = -math.pi / 2
# Act
result = rot_2d(angle)
# Assert
assert math.isclose(result[0][0], 0.0, abs_tol=1e-9)
assert math.isclose(result[0][1], 1.0, abs_tol=1e-9)
assert math.isclose(result[1][0], -1.0, abs_tol=1e-9)
assert math.isclose(result[1][1], 0.0, abs_tol=1e-9)
def test_rot_3d_x_axis_zero() -> None:
"""Testet die 3D-Rotation um die x-Achse um 0 Radiant."""
# Arrange
angle = 0.0
axis = "x"
# Act
result = rot_3d(angle, axis)
# Assert
expected = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
for row in range(3):
for col in range(3):
assert math.isclose(result[row][col], expected[row][col], abs_tol=1e-9)
def test_rot_3d_x_axis_pi_half() -> None:
"""Testet die 3D-Rotation um die x-Achse um pi / 2 Radiant."""
# Arrange
angle = math.pi / 2
axis = "x"
# Act
result = rot_3d(angle, axis)
# Assert
expected = [
[1.0, 0.0, 0.0],
[0.0, 0.0, -1.0],
[0.0, 1.0, 0.0],
]
for row in range(3):
for col in range(3):
assert math.isclose(result[row][col], expected[row][col], abs_tol=1e-9)
def test_rot_3d_y_axis_zero() -> None:
"""Testet die 3D-Rotation um die y-Achse um 0 Radiant."""
# Arrange
angle = 0.0
axis = "y"
# Act
result = rot_3d(angle, axis)
# Assert
expected = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
for row in range(3):
for col in range(3):
assert math.isclose(result[row][col], expected[row][col], abs_tol=1e-9)
def test_rot_3d_y_axis_pi_half() -> None:
"""Testet die 3D-Rotation um die y-Achse um pi / 2 Radiant."""
# Arrange
angle = math.pi / 2
axis = "y"
# Act
result = rot_3d(angle, axis)
# Assert
expected = [
[0.0, 0.0, 1.0],
[0.0, 1.0, 0.0],
[-1.0, 0.0, 0.0],
]
for row in range(3):
for col in range(3):
assert math.isclose(result[row][col], expected[row][col], abs_tol=1e-9)
def test_rot_3d_z_axis_zero() -> None:
"""Testet die 3D-Rotation um die z-Achse um 0 Radiant."""
# Arrange
angle = 0.0
axis = "z"
# Act
result = rot_3d(angle, axis)
# Assert
expected = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]
for row in range(3):
for col in range(3):
assert math.isclose(result[row][col], expected[row][col], abs_tol=1e-9)
def test_rot_3d_z_axis_pi_half() -> None:
"""Testet die 3D-Rotation um die z-Achse um pi / 2 Radiant."""
# Arrange
angle = math.pi / 2
axis = "z"
# Act
result = rot_3d(angle, axis)
# Assert
expected = [
[0.0, -1.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
]
for row in range(3):
for col in range(3):
assert math.isclose(result[row][col], expected[row][col], abs_tol=1e-9)
@pytest.mark.parametrize("invalid_axis", ["w", "123", "", "X", "Y", "Z"])
def test_rot_3d_invalid_axis(invalid_axis: str) -> None:
"""Testet, dass ungültige Achsen einen ValueError auslösen."""
# Arrange
angle = 1.0
# Act & Assert
with pytest.raises(ValueError, match="Ungültige Achse"):
rot_3d(angle, invalid_axis)