Perspektivische Projektion mit Tests ergänzen

This commit is contained in:
cmiku committed 2026-10-21 10:33:25 +02:00
1 parent a2c98da4d2
commit 3c3891d892
3 files changed
+97 -13

No files matched your search

+1 -1
View File
@@ -1,3 +1,3 @@
from .compute import matmul, transpose, rot_2D, rot_3D from .compute import matmul, transpose, rot_2D, rot_3D, project_perspective
# Damit project_ortho direkt aus matrixmania importiert werden kann. # Damit project_ortho direkt aus matrixmania importiert werden kann.
from .compute import project_ortho from .compute import project_ortho
+26
View File
@@ -201,7 +201,33 @@ def project_ortho(
# x und y skalieren und als Tupel zurückgeben. # x und y skalieren und als Tupel zurückgeben.
return (x * scale, y * scale) return (x * scale, y * scale)
def project_perspective(
point: tuple[float, float, float],
focal_length: float = 1.0,
scale: float = 1.0,
camera_distance: float = 4.0,
) -> tuple[float, float]:
"""Projiziert einen 3D-Punkt perspektivisch auf eine 2D-Ebene."""
# Wir verteilen die drei Koordinaten auf einzelne Variablen.
x, y, z = point
# Die Tiefe des Punktes wird um den Kameraabstand verschoben.
depth = z + camera_distance
# Durch 0 darf nicht geteilt werden.
# Ein Punkt auf der Kameraebene kann so nicht projiziert werden.
if depth == 0:
raise ValueError(
"Der Punkt darf nicht auf der Kameraebene liegen."
)
# Wir berechnen die horizontalen und vertikalen Bildschirmkoordinaten.
projected_x = x * focal_length / depth * scale
projected_y = y * focal_length / depth * scale
# Aus dem 3D-Punkt wird ein 2D-Punkt.
return projected_x, projected_y
if __name__ == "__main__": #führe den testcode nur aus wenn compute.py direkt gestartet wird if __name__ == "__main__": #führe den testcode nur aus wenn compute.py direkt gestartet wird
matrix_a = [ matrix_a = [
+70 -12
View File
@@ -1,30 +1,88 @@
# Wir importieren die Funktion, die wir testen möchten. # pytest hilft uns beim Testen und Vergleichen von Kommazahlen.
from matrixmania import project_ortho import pytest
# Wir importieren die Funktionen, die wir testen möchten.
from matrixmania import project_ortho, project_perspective
def test_project_ortho_without_scaling(): def test_project_ortho_without_scaling():
"""Prüft die Projektion mit dem Standardwert scale = 1.""" """Prüft die orthogonale Projektion mit Standardwerten."""
# Vorbereitung: einen 3D-Punkt festlegen. # Arrange: Einen 3D-Punkt vorbereiten.
point = (1.0, 2.0, 3.0) point = (1.0, 2.0, 3.0)
# Aufruf ohne scale: Die Funktion verwendet automatisch 1. # Act: Ohne zusätzliche Skalierung projizieren.
result = project_ortho(point) result = project_ortho(point)
# Erwartung: x und y bleiben gleich, z fällt weg. # Assert: x und y bleiben gleich, z fällt weg.
assert result == (1.0, 2.0) assert result == (1.0, 2.0)
def test_project_ortho_with_scaling(): def test_project_ortho_with_scaling():
"""Prüft die Projektion mit dem Skalierungsfaktor 100.""" """Prüft die orthogonale Projektion mit Skalierung 100."""
# Vorbereitung: denselben 3D-Punkt verwenden. # Arrange: Einen 3D-Punkt vorbereiten.
point = (1.0, 2.0, 3.0) point = (1.0, 2.0, 3.0)
# Aufruf mit scale = 100. # Act: Mit Skalierungsfaktor 100 projizieren.
result = project_ortho(point, scale=100) result = project_ortho(point, scale=100)
# Erwartung: x und y werden mit 100 multipliziert. # Assert: x und y werden jeweils mit 100 multipliziert.
# 1.0 * 100 = 100.0
# 2.0 * 100 = 200.0
assert result == (100.0, 200.0) assert result == (100.0, 200.0)
def test_project_perspective_without_scaling():
"""Prüft die perspektivische Projektion mit Standardwerten."""
# Arrange: Einen 3D-Punkt vorbereiten.
point = (1.0, 2.0, 3.0)
# Act: Die Standardwerte der Funktion verwenden.
result = project_perspective(point)
# Assert: Die Tiefe ist z + camera_distance = 3 + 4 = 7.
# Deshalb erwarten wir x = 1/7 und y = 2/7.
assert result == pytest.approx((1 / 7, 2 / 7))
def test_project_perspective_with_focal_length_and_scaling():
"""Prüft die Projektion mit Brennweite 2 und Skalierung 100."""
# Arrange: Einen 3D-Punkt vorbereiten.
point = (1.0, 2.0, 3.0)
# Act: Brennweite 2 und Skalierungsfaktor 100 verwenden.
result = project_perspective(point, focal_length=2, scale=100)
# Assert: Die Tiefe ist weiterhin 7.
# x = 1 * 2 / 7 * 100 = 200/7.
# y = 2 * 2 / 7 * 100 = 400/7.
assert result == pytest.approx((200 / 7, 400 / 7))
def test_project_perspective_with_custom_camera_distance():
"""Prüft die Projektion mit einem anderen Kameraabstand."""
# Arrange: Punkt und erwartetes Ergebnis vorbereiten.
# Die Tiefe ist z + camera_distance = 3 + 1 = 4.
point = (1.0, 2.0, 3.0)
expected = (0.25, 0.5)
# Act: Den Kameraabstand auf 1 setzen.
result = project_perspective(point, camera_distance=1.0)
# Assert: x = 1/4 und y = 2/4.
assert result == pytest.approx(expected)
def test_project_perspective_with_zero_scale():
"""Prüft die Projektion mit Skalierungsfaktor 0."""
# Arrange: Einen gültigen 3D-Punkt vorbereiten.
point = (1.0, 2.0, 3.0)
# Act: Den Skalierungsfaktor auf 0 setzen.
result = project_perspective(point, scale=0.0)
# Assert: Beide Koordinaten werden mit 0 multipliziert.
assert result == pytest.approx((0.0, 0.0))