asp_plot.csm_io
===============

.. py:module:: asp_plot.csm_io

.. autoapi-nested-parse::

   Camera-model I/O helpers mirrored from the NASA Ames Stereo Pipeline (ASP).

   The functions in this module are kept **function-based and as close to verbatim
   as practical** to the upstream ``orbit_plot.py`` so they can be re-synced when
   ASP changes. Do not refactor these into classes or rename them without a
   corresponding upstream change -- that would make future syncing painful.

   Upstream source:
   https://github.com/NeoGeographyToolkit/StereoPipeline/blob/master/src/asp/Tools/orbit_plot.py

   Related CSM/CsmUtils references are noted inline on the individual functions.



Attributes
----------

.. autoapisummary::

   asp_plot.csm_io.ASP_TO_CSM_SHIFT


Functions
---------

.. autoapisummary::

   asp_plot.csm_io.estim_satellite_orientation
   asp_plot.csm_io.getLineAtTime
   asp_plot.csm_io.getTimeAtLine
   asp_plot.csm_io.isLinescan
   asp_plot.csm_io.read_angles
   asp_plot.csm_io.read_csm_cam
   asp_plot.csm_io.read_frame_cam_dict
   asp_plot.csm_io.read_frame_csm_cam
   asp_plot.csm_io.read_linescan_pos_rot
   asp_plot.csm_io.read_positions_rotations
   asp_plot.csm_io.read_positions_rotations_from_file
   asp_plot.csm_io.read_tsai_cam
   asp_plot.csm_io.roll_pitch_yaw
   asp_plot.csm_io.toCsmPixel
   asp_plot.csm_io.tsai_list_to_gdf


Module Contents
---------------

.. py:function:: estim_satellite_orientation(positions)

   Estimate satellite orientation at each position.

   :param positions: List of satellite positions in ECEF coordinates
   :type positions: list of array-like

   :returns: List of rotation matrices representing satellite orientation
   :rtype: list of numpy.ndarray

   .. rubric:: Notes

   For each position, computes a local coordinate system where:
   - x axis is the direction of motion
   - z points roughly down (towards Earth center)
   - y is perpendicular to both x and z


.. py:function:: getLineAtTime(time, model)

   Get the line number at a given time in a linescan camera model.

   :param time: Time to convert to line number
   :type time: float
   :param model: CSM camera model parameters
   :type model: dict

   :returns: Line number corresponding to the given time
   :rtype: float

   :raises Exception: If the model does not have a linear relationship between time and lines

   .. rubric:: Notes

   This function computes the line number in the image corresponding
   to the given time, assuming a linear relationship between time and
   line number. Code adapted from get_line_at_time() in CsmUtils.cc.


.. py:function:: getTimeAtLine(model, line)

   Find the time at a given line in a linescan camera model.

   :param model: CSM camera model parameters
   :type model: dict
   :param line: Line number in the image (0-based)
   :type line: int

   :returns: Time corresponding to the given line
   :rtype: float

   .. rubric:: Notes

   The time is computed using the linear mapping between line number
   and time defined in the CSM model. Code adapted from get_time_at_line()
   in CsmUtils.cc and getImageTime() in UsgsAstroLsSensorModel.cpp.


.. py:function:: isLinescan(cam_file)

   Check if a camera file is for a linescan sensor.

   :param cam_file: Path to the camera file
   :type cam_file: str

   :returns: True if the camera is a linescan sensor, False otherwise
   :rtype: bool

   .. rubric:: Notes

   This function reads the first line of the camera file to check if
   it contains the string "LINE_SCAN", which indicates a linescan camera.


.. py:function:: read_angles(orig_cams, opt_cams, ref_cams)

   Extract and convert camera orientations to roll, pitch, yaw angles.

   :param orig_cams: List of paths to original camera files
   :type orig_cams: list of str
   :param opt_cams: List of paths to optimized camera files
   :type opt_cams: list of str
   :param ref_cams: List of paths to reference camera files (can be empty)
   :type ref_cams: list of str

   :returns: Tuple containing (orig_rotation_angles, opt_rotation_angles) where:
             - orig_rotation_angles is a list of Euler angles for original cameras
             - opt_rotation_angles is a list of Euler angles for optimized cameras
   :rtype: tuple

   :raises SystemExit: If the number of original and reference cameras don't match

   .. rubric:: Notes

   This function extracts the orientation of cameras and converts them
   to Euler angles (roll, pitch, yaw) relative to a reference orientation.
   If reference cameras are not provided, it estimates the reference
   orientation from the camera positions.


.. py:function:: read_csm_cam(json_file)

   Read a CSM model state file in JSON format.

   :param json_file: Path to the CSM JSON state file
   :type json_file: str

   :returns: Dictionary containing the CSM model parameters
   :rtype: dict

   .. rubric:: Notes

   CSM JSON files sometimes have text before the actual JSON content.
   This function handles that by finding the first open brace and
   parsing the JSON from that point.


.. py:function:: read_frame_cam_dict(cam)

   Read a frame camera model file into a dictionary.

   :param cam: Path to the camera file (.tsai or .json)
   :type cam: str

   :returns: Dictionary containing camera parameters
   :rtype: dict

   :raises Exception: If the file extension is not recognized


.. py:function:: read_frame_csm_cam(json_file)

   Read position and orientation from a CSM Frame camera file.

   :param json_file: Path to the CSM JSON state file
   :type json_file: str

   :returns: Dictionary containing camera center and rotation matrix
   :rtype: dict

   .. rubric:: Notes

   This function extracts the camera position and orientation from a
   CSM frame camera model. The camera position is given by the first three
   parameters, and the orientation is represented as a quaternion that
   is converted to a rotation matrix.


.. py:function:: read_linescan_pos_rot(json_file)

   Read positions and rotations from a CSM linescan camera file.

   :param json_file: Path to the CSM JSON state file
   :type json_file: str

   :returns: Tuple containing (positions, rotations) where:
             - positions is a list of camera positions
             - rotations is a list of rotation matrices
   :rtype: tuple

   .. rubric:: Notes

   Linescan cameras have different positions and orientations for each
   line in the image. This function extracts the full list of positions
   and orientations from the CSM model.


.. py:function:: read_positions_rotations(cams)

   Read positions and rotations from multiple camera files.

   :param cams: List of paths to camera files
   :type cams: list of str

   :returns: Tuple containing (positions, rotations) where:
             - positions is a list of camera positions
             - rotations is a list of rotation matrices
   :rtype: tuple

   :raises SystemExit: If the number of positions and rotations don't match

   .. rubric:: Notes

   This function reads all the camera files and concatenates their
   positions and rotations into single lists.


.. py:function:: read_positions_rotations_from_file(cam_file)

   Read positions and rotations from a camera file.

   :param cam_file: Path to the camera file
   :type cam_file: str

   :returns: Tuple containing (positions, rotations) where:
             - positions is a list of camera positions
             - rotations is a list of rotation matrices
   :rtype: tuple

   .. rubric:: Notes

   This function handles both linescan and frame cameras. For linescan
   cameras, it returns multiple positions and rotations corresponding
   to different lines in the image. For frame cameras, it returns a
   single position and rotation.


.. py:function:: read_tsai_cam(tsai)

   Read a TSAI frame camera model into a dictionary.

   :param tsai: Path to ASP frame camera model file (.tsai)
   :type tsai: str

   :returns: Dictionary containing camera model parameters
   :rtype: dict

   .. rubric:: Notes

   TSAI is a camera model format used by ASP. It contains parameters such as
   focal length, optical center, camera position, and orientation. See ASP
   documentation for more details:
   https://stereopipeline.readthedocs.io/en/latest/pinholemodels.html


.. py:function:: roll_pitch_yaw(rot_mat, ref_rot_mat)

   Calculate roll, pitch, and yaw angles relative to a reference orientation.

   :param rot_mat: Rotation matrix for the camera
   :type rot_mat: numpy.ndarray
   :param ref_rot_mat: Reference rotation matrix
   :type ref_rot_mat: numpy.ndarray

   :returns: Array of Euler angles [roll, pitch, yaw] in degrees
   :rtype: numpy.ndarray

   .. rubric:: Notes

   This function calculates the orientation of a camera relative to a
   reference orientation, and returns the result as Euler angles in
   roll, pitch, yaw (rotation around x, y, z axes) in degrees.


.. py:function:: toCsmPixel(asp_pix)

   Convert an ASP pixel coordinate to a CSM pixel coordinate.

   :param asp_pix: ASP pixel coordinates as [x, y]
   :type asp_pix: array-like

   :returns: CSM pixel coordinates
   :rtype: numpy.ndarray

   .. rubric:: Notes

   ASP and CSM use slightly different pixel coordinate conventions.
   CSM pixel coordinates are shifted by 0.5 pixels relative to ASP.
   Code copied from CsmModel.cc in ASP.


.. py:function:: tsai_list_to_gdf(tsai_fn_list)

   Convert a list of TSAI camera files to a GeoDataFrame.

   :param tsai_fn_list: List of paths to TSAI camera files
   :type tsai_fn_list: list of str

   :returns: GeoDataFrame containing camera model parameters with
             a Point geometry column for camera centers
   :rtype: geopandas.GeoDataFrame


.. py:data:: ASP_TO_CSM_SHIFT
   :value: 0.5


