Source code for ctapipe.coordinates.utils
import astropy.units as u
import numpy as np
from astropy.coordinates import AltAz
from erfa.ufunc import p2s as cartesian_to_spherical
from erfa.ufunc import s2p as spherical_to_cartesian
from .ground_frames import _get_xyz
__all__ = [
    "altaz_to_righthanded_cartesian",
    "get_point_on_shower_axis",
]
_zero_m = u.Quantity(0, u.m)
[docs]
def altaz_to_righthanded_cartesian(alt, az, distance=1.0):
    """Turns an alt/az coordinate into a 3d direction in a right-handed coordinate
    system.  This is because azimuths are in a left-handed system.
    See e.g: https://github.com/astropy/astropy/issues/5300
    Parameters
    ----------
    alt: u.Quantity
        altitude
    az: u.Quantity
        azimuth
    """
    # this is an optimization, shaves of ca. 50 % compared to handing over units
    # to the erfa function
    if hasattr(az, "unit"):
        az = az.to_value(u.rad)
        alt = alt.to_value(u.rad)
    unit = None
    if hasattr(distance, "unit"):
        unit = distance.unit
        distance = distance.value
    result = spherical_to_cartesian(-az, alt, distance)
    if unit is not None:
        return u.Quantity(result, unit=unit, copy=False)
    return result 
[docs]
@u.quantity_input(core_x=u.m, core_y=u.m, alt=u.rad, az=u.rad, distance=u.km)
def get_point_on_shower_axis(core_x, core_y, alt, az, telescope_position, distance):
    """
    Get a point on the shower axis in AltAz frame as seen by a telescope at the given position.
    Parameters
    ----------
    core_x : u.Quantity[length]
        Impact x-coordinate
    core_y : u.Quantity[length]
        Impact y-coordinate
    alt : u.Quantity[angle]
        Altitude of primary
    az : u.Quantity[angle]
        Azimuth of primary
    telescope_position : GroundFrame
        Telescope position
    distance : u.Quantity[length]
        Distance along the shower axis from the ground of the point returned.
    Returns
    -------
    coord : AltAz
        The AltAz coordinate of a point on the shower axis at the given distance
        from the impact point.
    """
    impact = u.Quantity([core_x, core_y, _zero_m], unit=u.m)
    # move up the shower axis by slant_distance
    point = impact + altaz_to_righthanded_cartesian(alt=alt, az=az, distance=distance)
    # offset by telescope positions and convert to sperical
    # to get local AltAz for each telescope
    cartesian = point[np.newaxis, :] - _get_xyz(telescope_position).T
    lon, lat, _ = cartesian_to_spherical(cartesian)
    return AltAz(alt=lat, az=-lon, copy=False)