a
    ߙfbz                     @   sh   d Z ddlmZ ddlZddlmZ ddlm	Z	 dd Z
d	d
 ZdddZdd Zdd ZdddZdS )zC
Utililies used for constructing and inspecting rotation matrices.
    )reduceN)units   )Anglec                  G   s   t tj| S )ax  Matrix multiply all arguments together.

    Arguments should have dimension 2 or larger. Larger dimensional objects
    are interpreted as stacks of matrices residing in the last two dimensions.

    This function mostly exists for readability: using `~numpy.matmul`
    directly, one would have ``matmul(matmul(m1, m2), m3)``, etc. For even
    better readability, one might consider using `~numpy.matrix` for the
    arguments (so that one could write ``m1 * m2 * m3``), but then it is not
    possible to handle stacks of matrices. Once only python >=3.5 is supported,
    this function can be replaced by ``m1 @ m2 @ m3``.
    )r   npmatmul)Zmatrices r   Clib/python3.9/site-packages/astropy/coordinates/matrix_utilities.pymatrix_product   s    r
   c                 C   s   |  ddS )aQ  Transpose a matrix or stack of matrices by swapping the last two axes.

    This function mostly exists for readability; seeing ``.swapaxes(-2, -1)``
    it is not that obvious that one does a transpose.  Note that one cannot
    use `~numpy.ndarray.T`, as this transposes all axes and thus does not
    work for stacks of matrices.
    )swapaxes)matrixr   r   r	   matrix_transpose   s    r   zc           	   
   C   s  t | tjr| tj} n(|du r.t| } nt|tj	| } t
| }t| }zd|}W n tyX   t|}|t|| jddd }|dtjf |dtjddf  d| dtjtjf  }tdd	D ]v}|d||f  |7  < |d
 d	 }|d d	 }|d||f  |d|f | 7  < |d||f  |d|f | 8  < qY nx0 |d
 d	 }|d d	 }tt| ddd }d|d||f< ||d||f< ||d||f< | |d||f< ||d||f< |S )aU  
    Generate matrices for rotation by some angle around some axis.

    Parameters
    ----------
    angle : angle-like
        The amount of rotation the matrices should represent.  Can be an array.
    axis : str or array-like
        Either ``'x'``, ``'y'``, ``'z'``, or a (x,y,z) specifying the axis to
        rotate about. If ``'x'``, ``'y'``, or ``'z'``, the rotation sense is
        counterclockwise looking down the + axis (e.g. positive rotations obey
        left-hand-rule).  If given as an array, the last dimension should be 3;
        it will be broadcast against ``angle``.
    unit : unit-like, optional
        If ``angle`` does not have associated units, they are in this
        unit.  If neither are provided, it is assumed to be degrees.

    Returns
    -------
    rmat : `numpy.matrix`
        A unitary rotation matrix.
    NZxyzr   T)axiskeepdims.      ?r      r      shaper   r   r   )
isinstanceuZQuantityZto_valueradianr   Zdeg2radZUnittoZradZsinZcosindex	TypeErrorZasarraysqrtsumZnewaxisrangezerosgetattr)	angler   ZunitsciRZa1Za2r   r   r	   rotation_matrix)   s<    


 "*r(   c                 C   s   t | }|jdd dkr$tdt |jdd }|d |d  |d< |d	 |d
  |d< |d |d  |d< t || jddd}t |d |d |d  |d  d }t|t	j
| | fS )av  
    Angle of rotation and rotation axis for a given rotation matrix.

    Parameters
    ----------
    matrix : array-like
        A 3 x 3 unitary rotation matrix (or stack of matrices).

    Returns
    -------
    angle : `~astropy.coordinates.Angle`
        The angle of rotation.
    axis : array
        The (normalized) axis of rotation (with last dimension 3).
    r   Nr   zmatrix is not 3x3r   ).r   r   ).r   r   ).r   ).r   r   ).r   r   ).r   ).r   r   ).r   r   ).r   T)r   ).r   r   ).r   r   ).r   r   r   )r   Z
asanyarrayr   
ValueErrorr!   r   r   Zarctan2r   r   r   )r   mr   rr#   r   r   r	   
angle_axish   s    

r,   c                 C   s:   t | jd }t jt j| | dd |dddd}|S )a  Check whether a matrix is in the length-preserving group O(3).

    Parameters
    ----------
    matrix : (..., N, N) array-like
        Must have attribute ``.shape`` and method ``.swapaxes()`` and not error
        when using `~numpy.isclose`.

    Returns
    -------
    is_o3 : bool or array of bool
        If the matrix has more than two axes, the O(3) check is performed on
        slices along the last two axes -- (M, N, N) => (M, ) bool array.

    Notes
    -----
    The orthogonal group O(3) preserves lengths, but is not guaranteed to keep
    orientations. Rotations and reflections are in this group.
    For more information, see https://en.wikipedia.org/wiki/Orthogonal_group
    r   r   gV瞯<)Zatol)r   r   )r   )r   Zidentityr   alliscloser   )r   Iis_o3r   r   r	   is_O3   s
    r1   Fc                 C   sD   t | }|r(tttj| d}nttj| d}||@ S )ah  Check whether a matrix is a rotation, proper or improper.

    Parameters
    ----------
    matrix : (..., N, N) array-like
        Must have attribute ``.shape`` and method ``.swapaxes()`` and not error
        when using `~numpy.isclose` and `~numpy.linalg.det`.
    allow_improper : bool, optional
        Whether to restrict check to the SO(3), the group of proper rotations,
        or also allow improper rotations (with determinant -1).
        The default (False) is only SO(3).

    Returns
    -------
    isrot : bool or array of bool
        If the matrix has more than two axes, the checks are performed on
        slices along the last two axes -- (M, N, N) => (M, ) bool array.

    See Also
    --------
    astopy.coordinates.matrix_utilities.is_O3 :
        For the less restrictive check that a matrix is in the group O(3).

    Notes
    -----
    The group SO(3) is the rotation group. It is O(3), with determinant 1.
    Rotations with determinant -1 are improper rotations, combining both a
    rotation and a reflection.
    For more information, see https://en.wikipedia.org/wiki/Orthogonal_group

    r   )r1   r   r.   absZlinalgZdet)r   Zallow_improperr0   Zis_det1r   r   r	   is_rotation   s
    !r3   )r   N)F)__doc__	functoolsr   Znumpyr   Zastropyr   r   Zanglesr   r
   r   r(   r,   r1   r3   r   r   r   r	   <module>   s   
?