Camera.centre() (src/multicam_sim/cameras.py:151) reads the camera position off R/t, but there's no getter for the direction the camera is looking — handy for logging, frustum checks, and "is this camera pointed the right way?" sanity tests.
Add Camera.forward() -> FloatArray: the world-space unit viewing direction.
Pointer: look_at_rotation (src/multicam_sim/geometry.py:32) stores the camera axes as the rows of R in the order [right, down, forward] (OpenCV convention, +z forward), so the forward axis is self.rotation()[2]. Put the getter next to centre() (cameras.py:151), returning a length-3 array.
Acceptance criteria
forward() returns a length-3 world-space unit vector (np.linalg.norm ≈ 1).
- Round-trip test: a camera from
Camera.look_at(0, intr, eye, target) has forward() ≈ normalize(target - eye).
- Pure read-only; no new dependency.
uv run mypy src, ruff check, ruff format --check, pytest green.
Camera.centre()(src/multicam_sim/cameras.py:151) reads the camera position offR/t, but there's no getter for the direction the camera is looking — handy for logging, frustum checks, and "is this camera pointed the right way?" sanity tests.Add
Camera.forward() -> FloatArray: the world-space unit viewing direction.Pointer:
look_at_rotation(src/multicam_sim/geometry.py:32) stores the camera axes as the rows ofRin the order[right, down, forward](OpenCV convention, +z forward), so the forward axis isself.rotation()[2]. Put the getter next tocentre()(cameras.py:151), returning a length-3 array.Acceptance criteria
forward()returns a length-3 world-space unit vector (np.linalg.norm ≈ 1).Camera.look_at(0, intr, eye, target)hasforward()≈normalize(target - eye).uv run mypy src,ruff check,ruff format --check,pytestgreen.