diff --git a/src/matrixmania/compute.py b/src/matrixmania/compute.py index c56df6f..e6a7c31 100644 --- a/src/matrixmania/compute.py +++ b/src/matrixmania/compute.py @@ -254,6 +254,54 @@ def project_ortho( 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]: + """Perspectively projects a 3D point onto the 2D plane. + + The x‑ and y‑coordinates are divided by the depth of the point, + so farther away points appear smaller than nearby ones:: + + x' = x * focal_length / (z + camera_distance) * scale + y' = y * focal_length / (z + camera_distance) * scale + + Parameters + ---------- + point : tuple[float, float, float] + 3D point ``(x, y, z)`` in model coordinates. + focal_length : float, optional + How strongly the perspective is visible, like the focal + length of a camera (default ``1.0``). + scale : float, optional + Factor the projected coordinates are multiplied with + (default ``1.0``, i.e. no scaling). + camera_distance : float, optional + Offset added to the z‑coordinate, i.e. the distance of the + camera from the scene (default ``4.0``). + + Returns + ------- + tuple[float, float] + 2D point ``(x', y')`` after perspective projection. + + Raises + ------ + ZeroDivisionError + If ``z + camera_distance`` is ``0`` (point on the camera plane). + + Notes + ----- + * A larger ``focal_length`` exaggerates the perspective; distant + points shrink, nearby points grow. + """ + x, y, z = point + depth = z + camera_distance + return (x * focal_length / depth * scale, y * focal_length / depth * scale) + + if __name__ == "__main__": # Beispiel 1: 2x3 × 3x2 a = [[1, 2, 3], [4, 5, 6]] @@ -303,6 +351,13 @@ if __name__ == "__main__": print("\nBeispiel 6 Projektion (0.5, -0.5, 10) mit scale=200:") print(project_ortho((0.5, -0.5, 10), scale=200)) + # Beispiel 7: Perspektivische Projektion (ferne Punkte wirken kleiner) + print("\nBeispiel 7 Perspektivische Projektion von (1, 2, 3):") + print(project_perspective((1.0, 2.0, 3.0))) + print(project_perspective((1.0, 2.0, 3.0), focal_length=2, scale=100)) + print("ferner Punkt (1, 2, 20) wirkt kleiner:") + print(project_perspective((1.0, 2.0, 20.0))) + # Docstring und Type Hints sind vorhanden und stimmen mit dem Code überein. # Fehlerfälle werden behandelt # Namen sind Aussagekräftig