U
    e»{jÏD  ã                   @   s  d Z ddlZddlmZ ddlZddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZmZ d
dddddgZdd„ Zdd„ Zdd„ ZG dd„ deƒZG dd„ deƒ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)Úreduce)Úunits)Úrotation_matrixé   )ÚModel)Ú	Parameter)Ú_to_orig_unitÚ
_to_radianÚRotateCelestial2NativeÚRotateNative2CelestialÚ
Rotation2DÚEulerAngleRotationÚRotationSequence3DÚSphericalRotationSequencec                 C   s^   g }t | |ƒD ]8\}}t|tjƒr(|j}| ¡ }| t||tjd�¡ qt	t
j|d d d… ƒS )N)Úunitéÿÿÿÿ)ÚzipÚ
isinstanceÚuÚQuantityÚvalueÚitemÚappendr   Úradr   ÚnpÚmatmul)ÚanglesÚ
axes_orderZmatricesÚangleZaxis© r   úY/var/www/html/bwave/python/venv/lib/python3.8/site-packages/astropy/modeling/rotations.pyÚ_create_matrix-   s    r!   c                 C   sV   t  | ¡} t  |¡}t  | ¡t  |¡ }t  |¡t  | ¡ }t  |¡}t  |||g¡S ©N)r   Zdeg2radÚcosÚsinÚarray)ÚalphaÚdeltaÚxÚyÚzr   r   r    Úspherical2cartesian7   s    


r+   c                 C   s8   t  | |¡}t  t  || ¡¡}t  t  ||¡¡}||fS r"   )r   ÚhypotZrad2degZarctan2)r(   r)   r*   Úhr&   r'   r   r   r    Úcartesian2spherical@   s    r.   c                       sV   e Zd ZdZdZdZdZdZeg e	e
dd�Zd‡ fdd„	Zed	d
„ ƒZdd„ Z‡  ZS )r   a¿  
    Perform a series of rotations about different axis in 3D space.

    Positive angles represent a counter-clockwise rotation.

    Parameters
    ----------
    angles : array-like
        Angles of rotation in deg in the order of axes_order.
    axes_order : str
        A sequence of 'x', 'y', 'z' corresponding to axis of rotation.

    Examples
    --------
    >>> model = RotationSequence3D([1.1, 2.1, 3.1, 4.1], axes_order='xyzx')

    Fé   z4Angles of rotation in deg in the order of axes_order©ÚdefaultÚgetterÚsetterÚdescriptionNc                    sŒ   dddg| _ t|ƒ | j ¡}|r8td|› d| j › d�ƒ‚|| _t|ƒt|ƒkrltdt|ƒ› dt|ƒ› d	�ƒ‚tƒ j||d
� d| _d| _	d S )Nr(   r)   r*   úUnrecognized axis label ú; should be one of ú zThe number of angles z! should match the number of axes Ú.)Úname)r(   r)   r*   )
ÚaxesÚsetÚ
differenceÚ
ValueErrorr   ÚlenÚsuperÚ__init__Ú_inputsÚ_outputs)Úselfr   r   r9   Úunrecognized©Ú	__class__r   r    r@   f   s    ÿÿzRotationSequence3D.__init__c                 C   s0   | j jddd… d }| j|| jddd… d�S )úInverse rotation.Nr   )r   )r   r   rF   r   )rC   r   r   r   r    Úinversew   s    zRotationSequence3D.inversec                 C   s–   |j |j ks|j |j kr tdƒ‚|j p(d}t | ¡ | ¡ | ¡ g¡}t t|d | jƒ|¡}|d |d |d   }}}| |_  |_ |_ |||fS )zJ
        Apply the rotation to a set of 3D Cartesian coordinates.
        ú,Expected input arrays to have the same shape©r   r   r   é   )Úshaper=   r   r%   ÚflattenÚdotr!   r   )rC   r(   r)   r*   r   Ú
orig_shapeÚinarrÚresultr   r   r    Úevaluate}   s    
zRotationSequence3D.evaluate)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Zstandard_broadcastingÚ
_separableÚn_inputsÚ	n_outputsr   r   r	   r   r@   ÚpropertyrH   rR   Ú__classcell__r   r   rE   r    r   G   s   ü
c                       sF   e Zd ZdZd‡ fdd„	Zedd„ ƒZedd„ ƒZ‡ fd	d
„Z‡  Z	S )r   a\  
    Perform a sequence of rotations about arbitrary number of axes
    in spherical coordinates.

    Parameters
    ----------
    angles : list
        A sequence of angles (in deg).
    axes_order : str
        A sequence of characters ('x', 'y', or 'z') corresponding to the
        axis of rotation and matching the order in ``angles``.

    Nc                    s6   d| _ d| _tƒ j|f||dœ|—Ž d| _d| _d S )NrK   )r   r9   )ÚlonÚlat)Ú	_n_inputsÚ
_n_outputsr?   r@   rA   rB   )rC   r   r   r9   ÚkwargsrE   r   r    r@   œ   s
    z"SphericalRotationSequence.__init__c                 C   s   | j S r"   )r^   ©rC   r   r   r    rX   £   s    z"SphericalRotationSequence.n_inputsc                 C   s   | j S r"   )r_   ra   r   r   r    rY   §   s    z#SphericalRotationSequence.n_outputsc           
         s@   t ||ƒ\}}}tƒ  ||||¡\}}}	t|||	ƒ\}}||fS r"   )r+   r?   rR   r.   )
rC   r\   r]   r   r(   r)   r*   Úx1Úy1Zz1rE   r   r    rR   «   s    z"SphericalRotationSequence.evaluate)N)
rS   rT   rU   rV   r@   rZ   rX   rY   rR   r[   r   r   rE   r    r   �   s   

c                   @   s<   e Zd ZdZ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   st   d }t |tjƒr&| ¡ }| ¡ }|j}t||ƒ}t|||g|ƒ}	t |	|¡}
t|
Ž \}}|d k	rl||_||_||fS r"   )	r   r   ÚndarrayrM   rL   r+   r!   rN   r.   )rC   r&   r'   ÚphiÚthetaÚpsir   rL   ZinpÚmatrixrQ   ÚaÚbr   r   r    rR   ¹   s    
z_EulerRotation.evaluateTc                 C   s   | j d tj| j d tjiS ©zInput units.r   r   ©Úinputsr   Údegra   r   r   r    Úinput_unitsÌ   s    z_EulerRotation.input_unitsc                 C   s   | j d tj| j d tjiS ©zOutput units.r   r   ©Úoutputsr   ro   ra   r   r   r    Úreturn_unitsÑ   s    z_EulerRotation.return_unitsN)rS   rT   rU   rV   rW   rR   Z_input_units_strictZ _input_units_allow_dimensionlessrZ   rp   rt   r   r   r   r    rd   ²   s   
rd   c                       sp   e Zd ZdZdZdZedeedd�Z	edeedd�Z
edeedd�Z‡ fdd	„Zed
d„ ƒZ‡ fdd„Z‡  ZS )r   a1  
    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` ['angle']
        "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.
    rK   r   z*1st Euler angle (Quantity or value in deg)r0   z*2nd Euler angle (Quantity or value in deg)z*3rd Euler angle (Quantity or value in deg)c                    s¬   dddg| _ t|ƒdkr&td|› �ƒ‚t|ƒ | j ¡}|rPtd|› d| j › �ƒ‚|| _dd	„ |||fD ƒ}t|ƒr‚t|ƒs‚td
ƒ‚t	ƒ j
f |||dœ|—Ž d| _d| _d S )Nr(   r)   r*   r/   z@Expected axes_order to be a character sequence of length 3, got r5   r6   c                 S   s   g | ]}t |tjƒ‘qS r   ©r   r   r   ©Ú.0Zparr   r   r    Ú
<listcomp>  s     z/EulerAngleRotation.__init__.<locals>.<listcomp>ú>All parameters should be of the same type - float or Quantity.)rf   rg   rh   )r&   r'   )r:   r>   Ú	TypeErrorr;   r<   r=   r   ÚanyÚallr?   r@   rA   rB   )rC   rf   rg   rh   r   r`   rD   ÚqsrE   r   r    r@   ÿ   s&    ÿÿÿzEulerAngleRotation.__init__c                 C   s*   | j | j | j | j | jd d d… d�S )Nr   )rf   rg   rh   r   )rF   rh   rg   rf   r   ra   r   r   r    rH     s    üzEulerAngleRotation.inversec                    s$   t ƒ  |||||| j¡\}}||fS r"   )r?   rR   r   )rC   r&   r'   rf   rg   rh   rj   rk   rE   r   r    rR     s    zEulerAngleRotation.evaluate)rS   rT   rU   rV   rX   rY   r   r   r	   rf   rg   rh   r@   rZ   rH   rR   r[   r   r   rE   r    r   ×   s2   üüü
c                       s\   e Zd ZdZedeedd�Zedeedd�Zedeedd�Z	‡ fdd„Z
‡ fd	d
„Z‡  ZS )Ú_SkyRotationzK
    Base class for RotateNative2Celestial and RotateCelestial2Native.
    r   ZLatituder0   Z
LongtitudezLongitude of a polec                    sJ   dd„ |||fD ƒ}t |ƒr,t|ƒs,tdƒ‚tƒ j|||f|Ž d| _d S )Nc                 S   s   g | ]}t |tjƒ‘qS r   ru   rv   r   r   r    rx   7  s     z)_SkyRotation.__init__.<locals>.<listcomp>ry   Zzxz)r{   r|   rz   r?   r@   r   )rC   r\   r]   Úlon_poler`   r}   rE   r   r    r@   6  s    ÿz_SkyRotation.__init__c           	         sR   t ƒ  |||||| j¡\}}|dk }t|tjƒrB||  d7  < n|d7 }||fS )Nr   ih  )r?   rR   r   r   r   re   )	rC   rf   rg   r\   r]   r   r&   r'   ÚmaskrE   r   r    Ú	_evaluate?  s    z_SkyRotation._evaluate)rS   rT   rU   rV   r   r   r	   r\   r]   r   r@   r�   r[   r   r   rE   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 `~astropy.units.Quantity` ['angle']
        Celestial longitude of the fiducial point.
    lat : float or `~astropy.units.Quantity` ['angle']
        Celestial latitude of the fiducial point.
    lon_pole : float or `~astropy.units.Quantity` ['angle']
        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. Inputs are angles on the native sphere.
    Outputs are angles on the celestial sphere.
    rK   c                 C   s   | j d tj| j d tjiS rl   rm   ra   r   r   r    rp   `  s    z"RotateNative2Celestial.input_unitsc                 C   s   | j d tj| j d tjiS rq   rr   ra   r   r   r    rt   e  s    z#RotateNative2Celestial.return_unitsc                    s$   t ƒ j|||f|Ž d| _d| _d S )N©Úphi_NÚtheta_N©Úalpha_CÚdelta_C©r?   r@   rn   rs   ©rC   r\   r]   r   r`   rE   r   r    r@   j  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 or `~astropy.units.Quantity` ['angle']
            Angles in the Native coordinate system.
            it is assumed that numerical only inputs are in degrees.
            If float, assumed in degrees.
        lon, lat, lon_pole : float or `~astropy.units.Quantity` ['angle']
            Parameter values when the model was initialized.
            If float, assumed in degrees.

        Returns
        -------
        alpha_C, delta_C : float or `~astropy.units.Quantity` ['angle']
            Angles on the Celestial sphere.
            If float, in degrees.
        rK   ©r   r   r   r   r   Úpir?   r�   )rC   rƒ   r„   r\   r]   r   rf   rg   rh   r†   r‡   rE   r   r    rR   o  s    zRotateNative2Celestial.evaluatec                 C   s   t | j| j| jƒS r"   )r
   r\   r]   r   ra   r   r   r    rH   �  s    zRotateNative2Celestial.inverse©rS   rT   rU   rV   rX   rY   rZ   rp   rt   r@   rR   rH   r[   r   r   rE   r    r   I  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 `~astropy.units.Quantity` ['angle']
        Celestial longitude of the fiducial point.
    lat : float or `~astropy.units.Quantity` ['angle']
        Celestial latitude of the fiducial point.
    lon_pole : float or `~astropy.units.Quantity` ['angle']
        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. Inputs are angles on the celestial sphere.
    Outputs are angles on the native sphere.
    rK   c                 C   s   | j d tj| j d tjiS rl   rm   ra   r   r   r    rp   ª  s    z"RotateCelestial2Native.input_unitsc                 C   s   | j d tj| j d tjiS rq   rr   ra   r   r   r    rt   ¯  s    z#RotateCelestial2Native.return_unitsc                    s$   t ƒ j|||f|Ž d| _d| _d S )Nr…   r‚   rˆ   r‰   rE   r   r    r@   ´  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 or `~astropy.units.Quantity` ['angle']
            Angles in the Celestial coordinate frame.
            If float, assumed in degrees.
        lon, lat, lon_pole : float or `~astropy.units.Quantity` ['angle']
            Parameter values when the model was initialized.
            If float, assumed in degrees.

        Returns
        -------
        phi_N, theta_N : float or `~astropy.units.Quantity` ['angle']
            Angles on the Native sphere.
            If float, in degrees.

        rK   rŠ   )rC   r†   r‡   r\   r]   r   rf   rg   rh   rƒ   r„   rE   r   r    rR   ¼  s    zRotateCelestial2Native.evaluatec                 C   s   t | j| j| jƒS r"   )r   r\   r]   r   ra   r   r   r    rH   Ú  s    zRotateCelestial2Native.inverserŒ   r   r   rE   r    r
   “  s   

c                       sd   e Zd ZdZdZdZdZedee	dd�Z
e
f‡ fdd„	Zed	d
„ ƒZedd„ ƒZedd„ ƒZ‡  Z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']
        Angle of rotation (if float it should be in deg).
    rK   Fg        z,Angle of rotation (Quantity or value in deg)r0   c                    s&   t ƒ jf d|i|—Ž d| _d| _d S )Nr   )r(   r)   )r?   r@   rA   rB   )rC   r   r`   rE   r   r    r@   ÷  s    zRotation2D.__init__c                 C   s   | j | j d�S )rG   ©r   )rF   r   ra   r   r   r    rH   ü  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  }}| |_ |_ |røtj||dd	�tj||dd	�fS ||fS )
a  
        Rotate (x, y) about ``angle``.

        Parameters
        ----------
        x, y : array-like
            Input quantities
        angle : float or `~astropy.units.Quantity` ['angle']
            Angle of rotations.
            If float, assumed in degrees.

        rI   r   Nz"x and y must have compatible unitsrJ   r   r   T)r   Zsubok)rL   r=   ÚgetattrZis_equivalentÚtor   Z
UnitsErrorr   r%   rM   r   r   Zto_valuer   rN   Ú_compute_matrix)
Úclsr(   r)   r   Zx_unitZy_unitZ	has_unitsrO   rP   rQ   r   r   r    rR     s0    


  ÿzRotation2D.evaluatec                 C   s6   t jt | ¡t | ¡ gt | ¡t | ¡ggt jd�S )N)Zdtype)r   r%   Úmathr#   r$   Zfloat64r�   r   r   r    r�   .  s    (þzRotation2D._compute_matrix)rS   rT   rU   rV   rX   rY   rW   r   r   r	   r   r@   rZ   rH   ÚclassmethodrR   Ústaticmethodr�   r[   r   r   rE   r    r   ß  s"   ü

+)rV   r’   Ú	functoolsr   Únumpyr   Zastropyr   r   Z$astropy.coordinates.matrix_utilitiesr   Úcorer   Ú
parametersr   Úutilsr   r	   Ú__all__r!   r+   r.   r   r   rd   r   r~   r   r
   r   r   r   r   r    Ú<module>   s4   ú

	F%%M%JL