Perspektivische Projektion mit Tests ergänzen
This commit is contained in:
1 parent
a2c98da4d2
commit
3c3891d892
3 files changed
+97
-13
No files matched your search
@@ -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
|
||||||
@@ -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 = [
|
||||||
|
|||||||
@@ -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))
|
||||||
Reference in new issue
Block a user