camera_roll_wrt_solar_north

camera_roll_wrt_solar_north#

camera_roll_wrt_solar_north(
position,
focal_point,
view_up,
world_up=array([0, 0, 1]),
degrees=True,
)[source]#

Compute the camera roll angle relative to a world “up” direction (default: solar north).

The roll is defined as the signed rotation about the view axis (from camera position toward focal_point) that would align the projection of world_up onto the camera image plane with the camera’s current view_up direction (also projected onto the image plane).

Parameters:
positionarray_like, shape (3,)

Camera position in world coordinates.

focal_pointarray_like, shape (3,)

Camera focal point (look-at target) in world coordinates.

view_uparray_like, shape (3,)

Camera “up” vector in world coordinates (need not be perfectly orthogonal to the view direction; it will be projected into the view plane).

world_uparray_like, shape (3,), optional

Reference “up” direction in world coordinates. Defaults to SOLAR_NORTH. This is projected into the view plane before computing the roll.

degreesbool, optional

If True, return the roll angle in degrees. If False, return radians.

Returns:
rollfloat

Signed roll angle about the view axis. Positive follows the right-hand rule about the view direction vector (focal_point - position).

If the roll is undefined (e.g., gimbal / degenerate cases), returns np.nan.

Notes

Algorithm: 1. Compute the normalized view direction v = normalize(focal_point - position). 2. Normalize view_up and world_up and project each onto the plane

perpendicular to v (the image plane): u_perp = u - (u·v) v and w_perp = w - (w·v) v.

  1. Compute the signed angle from w_perp to u_perp about axis v using:

    ang = atan2( v · (w_perp × u_perp), w_perp · u_perp )

The angle is undefined when the projection of world_up (or view_up) onto the view plane has near-zero magnitude — most commonly when the view direction is parallel (or anti-parallel) to world_up (a gimbal-like case).

Examples

>>> roll = camera_roll_wrt_solar_north(
...     position=(10, 0, 0),
...     focal_point=(0, 0, 0),
...     view_up=(0, 0, 1),
... )
>>> np.isfinite(roll)
True