B
    q\3                 @   s   d Z ddlZddlZddlmZ ddlmZ ddlm	Z	m
Z
 ddlmZ ddlmZ dd	lmZmZ d
dddgZG dd dZG dd deeZG dd deeZG dd deZG dd
 d
eZG dd deZdS )a  
Implements rotations, including spherical rotations as defined in WCS Paper II
[1]_

`RotateNative2Celestial` and `RotateCelestial2Native` follow the convention in
WCS Paper II to rotate to/from a native sphere and the celestial sphere.

The implementation uses `EulerAngleRotation`. The model parameters are
three angles: the longitude (``lon``) and latitude (``lat``) of the fiducial point
in the celestial system (``CRVAL`` keywords in FITS), and the longitude of the celestial
pole in the native system (``lon_pole``). The Euler angles are ``lon+90``, ``90-lat``
and ``-(lon_pole-90)``.


References
----------
.. [1] Calabretta, M.R., Greisen, E.W., 2002, A&A, 395, 1077 (Paper II)
    N   )Model)	Parameter)rotation_matrixmatrix_product)units)
deprecated)
_to_radian_to_orig_unitRotateCelestial2NativeRotateNative2Celestial
Rotation2DEulerAngleRotationc               @   sp   e Zd ZdZdZdd Zedd Zedd Ze	d	ed
d Z
dd ZdZdZedd Zedd ZdS )_EulerRotationz7
    Base class which does the actual computation.
    Fc       	      C   sh   g }xLt |||g|D ]8\}}t|tjr0|j}| }|t||tjd qW t	|d d d  }|S )N)unit)
zip
isinstanceuQuantityvalueitemappendr   radr   )	selfphithetapsi
axes_orderZmatricesangleZaxisresult r!   9lib/python3.7/site-packages/astropy/modeling/rotations.py_create_matrix,   s    z_EulerRotation._create_matrixc             C   sV   t | } t |}t | t | }t |t |  }t |}t |||gS )N)npZdeg2radcossinarray)alphadeltaxyzr!   r!   r"   spherical2cartesian6   s    


z"_EulerRotation.spherical2cartesianc             C   s8   t | |}t t || }t t ||}||fS )N)r$   ZhypotZrad2degZarctan2)r*   r+   r,   hr(   r)   r!   r!   r"   cartesian2spherical?   s    z"_EulerRotation.cartesian2sphericalg       @c             C   s0   t t| t| gt|  t| ggS )z
        Clockwise rotation matrix.

        Parameters
        ----------
        angle : float
            Rotation angle in radians.
        )r$   r'   mathr%   r&   )r   r!   r!   r"   rotation_matrix_from_angleF   s    z)_EulerRotation.rotation_matrix_from_anglec             C   s   d }t |tjr0|jdkr0| }| }|j}| ||}| ||||}	t|	|}
| j	|
 \}}|d k	rz||_||_||fS )N   )
r   r$   ndarrayndimflattenshaper-   r#   dotr/   )r   r(   r)   r   r   r   r   r6   ZinpZmatrixr    abr!   r!   r"   evaluateT   s    z_EulerRotation.evaluateTc             C   s   t jt jdS )z Input units. )r(   r)   )r   deg)r   r!   r!   r"   input_unitsg   s    z_EulerRotation.input_unitsc             C   s   t jt jdS )z Output units. )r(   r)   )r   r;   )r   r!   r!   r"   return_unitsl   s    z_EulerRotation.return_unitsN)__name__
__module____qualname____doc__
_separabler#   staticmethodr-   r/   r   r1   r:   Z_input_units_strictZ _input_units_allow_dimensionlesspropertyr<   r=   r!   r!   r!   r"   r   %   s   
	r   c                   sf   e Zd ZdZdZdZedeedZ	edeedZ
edeedZ fddZdd Z fd	d
Z  ZS )r   a'  
    Implements Euler angle intrinsic rotations.

    Rotates one coordinate system into another (fixed) coordinate system.
    All coordinate systems are right-handed. The sign of the angles is
    determined by the right-hand rule..

    Parameters
    ----------
    phi, theta, psi : float or `~astropy.units.Quantity`
        "proper" Euler angles in deg.
        If floats, they should be in deg.
    axes_order : str
        A 3 character string, a combination of 'x', 'y' and 'z',
        where each character denotes an axis in 3D space.
    )r(   r)   r   )defaultgettersetterc                s   dddg| _ t|dkr&td|t|| j }|rLtd|| j || _dd |||gD }t|r~t	|s~td	t
 jf |||d
| d S )Nr*   r+   r,      zBExpected axes_order to be a character sequence of length 3,got {0}z2Unrecognized axis label {0}; should be one of {1} c             S   s   g | ]}t |tjqS r!   )r   r   r   ).0parr!   r!   r"   
<listcomp>   s    z/EulerAngleRotation.__init__.<locals>.<listcomp>z>All parameters should be of the same type - float or Quantity.)r   r   r   )Zaxeslen	TypeErrorformatset
difference
ValueErrorr   anyallsuper__init__)r   r   r   r   r   kwargsZunrecognizedqs)	__class__r!   r"   rU      s    zEulerAngleRotation.__init__c             C   s*   | j | j | j | j | jd d d dS )Nr   )r   r   r   r   )rX   r   r   r   r   )r   r!   r!   r"   inverse   s    
zEulerAngleRotation.inversec                s$   t  |||||| j\}}||fS )N)rT   r:   r   )r   r(   r)   r   r   r   r8   r9   )rX   r!   r"   r:      s    zEulerAngleRotation.evaluate)r>   r?   r@   rA   inputsoutputsr   r
   r	   r   r   r   rU   rY   r:   __classcell__r!   r!   )rX   r"   r   r   s   c                   sV   e Zd ZdZedeedZedeedZedeedZ	 fddZ
 fddZ  ZS )_SkyRotationzK
    Base class for RotateNative2Celestial and RotateCelestial2Native.
    r   )rE   rF   rG   c                sJ   dd |||gD }t |r,t|s,tdt j|||f| d| _d S )Nc             S   s   g | ]}t |tjqS r!   )r   r   r   )rI   rJ   r!   r!   r"   rK      s    z)_SkyRotation.__init__.<locals>.<listcomp>z>All parameters should be of the same type - float or Quantity.Zzxz)rR   rS   rM   rT   rU   r   )r   lonlatlon_polerV   rW   )rX   r!   r"   rU      s
    z_SkyRotation.__init__c       	         sR   t  |||||| j\}}|dk }t|tjrB||  d7  < n|d7 }||fS )Nr   ih  )rT   r:   r   r   r$   r3   )	r   r   r   r^   r_   r`   r(   r)   mask)rX   r!   r"   	_evaluate   s    z_SkyRotation._evaluate)r>   r?   r@   rA   r   r
   r	   r^   r_   r`   rU   rb   r\   r!   r!   )rX   r"   r]      s   r]   c                   sX   e Zd ZdZdZdZedd Zedd Z fdd	Z	 fd
dZ
edd Z  ZS )r   a  
    Transform from Native to Celestial Spherical Coordinates.

    Parameters
    ----------
    lon : float or or `~astropy.units.Quantity`
        Celestial longitude of the fiducial point.
    lat : float or or `~astropy.units.Quantity`
        Celestial latitude of the fiducial point.
    lon_pole : float or or `~astropy.units.Quantity`
        Longitude of the celestial pole in the native system.

    Notes
    -----
    If ``lon``, ``lat`` and ``lon_pole`` are numerical values they should be in units of deg.
    )phi_Ntheta_N)alpha_Cdelta_Cc             C   s   t jt jdS )z Input units. )rc   rd   )r   r;   )r   r!   r!   r"   r<      s    z"RotateNative2Celestial.input_unitsc             C   s   t jt jdS )z Output units. )re   rf   )r   r;   )r   r!   r!   r"   r=      s    z#RotateNative2Celestial.return_unitsc                s   t  j|||f| d S )N)rT   rU   )r   r^   r_   r`   rV   )rX   r!   r"   rU      s    zRotateNative2Celestial.__init__c                sl   t |tjr|j}|j}|j}|tjd  }tjd |  }tjd |  }t |||||\}	}
|	|
fS )a  
        Parameters
        ----------
        phi_N, theta_N : float (deg) or `~astropy.units.Quantity`
            Angles in the Native coordinate system.
        lon, lat, lon_pole : float (in deg) or `~astropy.units.Quantity`
            Parameter values when the model was initialized.

        Returns
        -------
        alpha_C, delta_C : float (deg) or `~astropy.units.Quantity`
            Angles on the Celestial sphere.
        r2   )r   r   r   r   r$   pirT   rb   )r   rc   rd   r^   r_   r`   r   r   r   re   rf   )rX   r!   r"   r:      s    zRotateNative2Celestial.evaluatec             C   s   t | j| j| jS )N)r   r^   r_   r`   )r   r!   r!   r"   rY     s    zRotateNative2Celestial.inverse)r>   r?   r@   rA   rZ   r[   rD   r<   r=   rU   r:   rY   r\   r!   r!   )rX   r"   r      s   c                   sX   e Zd ZdZdZdZedd Zedd Z fdd	Z	 fd
dZ
edd Z  ZS )r   a  
    Transform from Celestial to Native Spherical Coordinates.

    Parameters
    ----------
    lon : float or or `~astropy.units.Quantity`
        Celestial longitude of the fiducial point.
    lat : float or or `~astropy.units.Quantity`
        Celestial latitude of the fiducial point.
    lon_pole : float or or `~astropy.units.Quantity`
        Longitude of the celestial pole in the native system.

    Notes
    -----
    If ``lon``, ``lat`` and ``lon_pole`` are numerical values they should be in units of deg.
    )re   rf   )rc   rd   c             C   s   t jt jdS )z Input units. )re   rf   )r   r;   )r   r!   r!   r"   r<     s    z"RotateCelestial2Native.input_unitsc             C   s   t jt jdS )z Output units. )rc   rd   )r   r;   )r   r!   r!   r"   r=   $  s    z#RotateCelestial2Native.return_unitsc                s   t  j|||f| d S )N)rT   rU   )r   r^   r_   r`   rV   )rX   r!   r"   rU   )  s    zRotateCelestial2Native.__init__c                sj   t |tjr|j}|j}|j}tjd | }tjd | }|tjd   }t |||||\}	}
|	|
fS )a  
        Parameters
        ----------
        alpha_C, delta_C : float (deg) or `~astropy.units.Quantity`
            Angles in the Celestial coordinate frame.
        lon, lat, lon_pole : float (deg) or `~astropy.units.Quantity`
            Parameter values when the model was initialized.

        Returns
        -------
        phi_N, theta_N : float (deg) or `~astropy.units.Quantity`
            Angles on the Native sphere.

        r2   )r   r   r   r   r$   rg   rT   rb   )r   re   rf   r^   r_   r`   r   r   r   rc   rd   )rX   r!   r"   r:   ,  s    zRotateCelestial2Native.evaluatec             C   s   t | j| j| jS )N)r   r^   r_   r`   )r   r!   r!   r"   rY   G  s    zRotateCelestial2Native.inverse)r>   r?   r@   rA   rZ   r[   rD   r<   r=   rU   r:   rY   r\   r!   r!   )rX   r"   r     s   c               @   sN   e Zd ZdZdZdZdZedee	dZ
edd Zedd	 Zed
d ZdS )r   a  
    Perform a 2D rotation given an angle.

    Positive angles represent a counter-clockwise rotation and vice-versa.

    Parameters
    ----------
    angle : float or `~astropy.units.Quantity`
        Angle of rotation (if float it should be in deg).
    )r*   r+   Fg        )rE   rF   rG   c             C   s   | j | j dS )zInverse rotation.)r   )rX   r   )r   r!   r!   r"   rY   ^  s    zRotation2D.inversec       
      C   s   |j |j krtdt|dd}t|dd}|dk	o:|dk	}||krl|rb||rb||}|}n
td|j ptd}t|	 |	 g}t
|tjr|tj}t| ||}	|	d |	d  }}| |_ |_ |rtj||dtj||dfS ||fS dS )	z
        Rotate (x, y) about ``angle``.

        Parameters
        ----------
        x, y : ndarray-like
            Input quantities
        angle : float (deg) or `~astropy.units.Quantity`
            Angle of rotations.

        z,Expected input arrays to have the same shaper   Nz"x and y must have compatible units)r   r   r   )r   )r6   rQ   getattrZis_equivalenttor   Z
UnitsErrorr$   r'   r5   r   r   Zto_valuer   r7   _compute_matrix)
clsr*   r+   r   Zx_unitZy_unitZ	has_unitsZ
orig_shapeZinarrr    r!   r!   r"   r:   d  s(    


zRotation2D.evaluatec             C   s6   t jt| t|  gt| t| ggt jdS )N)Zdtype)r$   r'   r0   r%   r&   Zfloat64)r   r!   r!   r"   rj     s    zRotation2D._compute_matrixN)r>   r?   r@   rA   rZ   r[   rB   r   r
   r	   r   rD   rY   classmethodr:   rC   rj   r!   r!   r!   r"   r   L  s   
*)rA   r0   Znumpyr$   Zcorer   Z
parametersr   Z$astropy.coordinates.matrix_utilitiesr   r   Zastropyr   r   Zastropy.utils.decoratorsr   Zutilsr	   r
   __all__r   r   r]   r   r   r   r!   r!   r!   r"   <module>   s    M5EE