a
    d"*                     @   s   d dl mZ d dlmZmZ d dlmZmZmZm	Z	m
Z
mZmZ d dlmZmZmZmZ d dlmZmZmZ G dd deZdS )	    )pi)TupleUnion)Module	ParameterTensor	as_tensorconcatenaterandstack)QuaternionCoeffOrdernormalize_quaternionquaternion_to_rotation_matrixrotation_matrix_to_quaternion)KORNIA_CHECKKORNIA_CHECK_SHAPEKORNIA_CHECK_TYPEc                       s@  e Zd ZdZedd fddZedddZd	d
 Zd dddZ	d d dddZ
d d dddZd d dddZeed f d dddZd d dddZeedddZeedddZeedddZeedddZeedd d!Zeedd"d#Zeedd$d%Zeedd&d'Zeedd(d)Zeedd*d+Zeeed,f dd-d.Zeedd/d0Zedd1d2Ze ed d3d4d5Z!e ed d6d7d8Z"e e#e#e#e#d d9d:d;Z$e ed d6d<d=Z%edd>d?Z&d dd@dAZ'd ddBdCZ(d ddDdEZ)eddFdGZ*dLdHdIZ+dJdK Z,  Z-S )M
Quaterniona`  Base class to represent a Quaternion.

    A quaternion is a four dimensional vector representation of a rotation transformation in 3d.
    See more: https://en.wikipedia.org/wiki/Quaternion

    The general definition of a quaternion is given by:

    .. math ::

        Q = a + b \cdot \mathbf{i} + c \cdot \mathbf{j} + d \cdot \mathbf{k}

    Thus, we represent a rotation quaternion as a contiguous tensor structure to
    perform rigid bodies transformations:

    .. math ::

        Q = \begin{bmatrix} q_w & q_x & q_y & q_z \end{bmatrix}

    Example:
        >>> q = Quaternion.identity(batch_size=4)
        >>> q.data
        Parameter containing:
        tensor([[1., 0., 0., 0.],
                [1., 0., 0., 0.],
                [1., 0., 0., 0.],
                [1., 0., 0., 0.]], requires_grad=True)
        >>> q.real
        tensor([[1.],
                [1.],
                [1.],
                [1.]], grad_fn=<SliceBackward0>)
        >>> q.vec
        tensor([[0., 0., 0.],
                [0., 0., 0.],
                [0., 0., 0.],
                [0., 0., 0.]], grad_fn=<SliceBackward0>)
    N)datareturnc                    s&   t    t|ddg t|| _dS )a  Constructor for the base class.

        Args:
            data: tensor containing the quaternion data with the sape of :math:`(B, 4)`.

        Example:
            >>> data = torch.rand(2, 4)
            >>> q = Quaternion(data)
            >>> q.shape
            (2, 4)
        B4N)super__init__r   r   _data)selfr   	__class__ c/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/kornia/geometry/quaternion.pyr   9   s    
zQuaternion.__init__)r   c                 C   s   d| j  d| j S )Nzreal: z 
vec: )realvecr   r   r   r   __repr__I   s    zQuaternion.__repr__c                 C   s
   | j | S Nr   )r   idxr   r   r   __getitem__L   s    zQuaternion.__getitem__c                 C   s   t | j S )zInverts the sign of the quaternion data.

        Example:
            >>> q = Quaternion.identity(batch_size=1)
            >>> -q.data
            tensor([[-1., -0., -0., -0.]], grad_fn=<NegBackward0>)
        )r   r   r"   r   r   r   __neg__O   s    zQuaternion.__neg__)rightr   c                 C   s   t |t t| j|j S )ap  Add a given quaternion.

        Args:
            right: the quaternion to add.

        Example:
            >>> q1 = Quaternion.identity(batch_size=1)
            >>> q2 = Quaternion(Tensor([[2., 0., 1., 1.]]))
            >>> q3 = q1 + q2
            >>> q3.data
            Parameter containing:
            tensor([[3., 0., 1., 1.]], requires_grad=True)
        r   r   r   r   r)   r   r   r   __add__Y   s    
zQuaternion.__add__c                 C   s   t |t t| j|j S )az  Subtract a given quaternion.

        Args:
            right: the quaternion to subtract.

        Example:
            >>> q1 = Quaternion(Tensor([[2., 0., 1., 1.]]))
            >>> q2 = Quaternion.identity(batch_size=1)
            >>> q3 = q1 - q2
            >>> q3.data
            Parameter containing:
            tensor([[1., 0., 1., 1.]], requires_grad=True)
        r*   r+   r   r   r   __sub__j   s    
zQuaternion.__sub__c                 C   s^   t |t | j|j | | j|j }| j|j |j| j  | j|j }tt||fdS N)r   r   r    _batched_squared_normr!   Zcrossr	   )r   r)   Znew_realZnew_vecr   r   r   __mul__{   s    
&zQuaternion.__mul__c                 C   s.   t |trt| j| S t|t | |  S r$   )
isinstancer   r   r   r   invr+   r   r   r   __div__   s    

zQuaternion.__div__c                 C   s
   |  |S r$   )r4   r+   r   r   r   __truediv__   s    zQuaternion.__truediv__c                 C   s   | j S )z4Return the underlying data with shape :math:`(B,4).`r   r"   r   r   r   r      s    zQuaternion.datac                 C   s   | j S zReturn the underlying data with shape :math:`(B,4)`.

        Alias for :func:`~kornia.geometry.quaternion.Quaternion.data`
        r6   r"   r   r   r   coeffs   s    zQuaternion.coeffsc                 C   s   | j S )z{Return the real part with shape :math:`(B,1)`.

        Alias for :func:`~kornia.geometry.quaternion.Quaternion.w`
        )wr"   r   r   r   r       s    zQuaternion.realc                 C   s   | j dddf S )zCReturn the vector with the imaginary part with shape :math:`(B,3)`..   Nr%   r"   r   r   r   r!      s    zQuaternion.vecc                 C   s   | j S r7   r%   r"   r   r   r   q   s    zQuaternion.qc                 C   s   | j S )zReturn a scalar with the real with shape :math:`(B,1)`.

        Alias for :func:`~kornia.geometry.quaternion.Quaternion.w`
        )r    r"   r   r   r   scalar   s    zQuaternion.scalarc                 C   s   | j dddf S )z0Return the :math:`q_w` with shape :math:`(B,1)`..r   r:   r%   r"   r   r   r   r9      s    zQuaternion.wc                 C   s   | j dddf S )z0Return the :math:`q_x` with shape :math:`(B,1)`..r:      r%   r"   r   r   r   x   s    zQuaternion.xc                 C   s   | j dddf S )z0Return the :math:`q_y` with shape :math:`(B,1)`..r=      r%   r"   r   r   r   y   s    zQuaternion.yc                 C   s   | j dddf S )z0Return the :math:`q_z` with shape :math:`(B,1)`..r?      r%   r"   r   r   r   z   s    zQuaternion.z.c                 C   s   t | jjS )zAReturn the shape of the underlying data with shape :math:`(B,4)`.)tupler   shaper"   r   r   r   rD      s    zQuaternion.shapec                 C   s   | j |    S )zReturn the polar angle with shape :math:`(B,1)`.

        Example:
            >>> q = Quaternion.identity(batch_size=1)
            >>> q.polar_angle
            tensor([[0.]], grad_fn=<AcosBackward0>)
        )r<   normacosr"   r   r   r   polar_angle   s    	zQuaternion.polar_anglec                 C   s   t | jtjdS )aK  Convert the quaternion to a rotation matrix of shape :math:`(B,3,3)`.

        Example:
            >>> q = Quaternion.identity(batch_size=1)
            >>> m = q.matrix()
            >>> m
            tensor([[[1., 0., 0.],
                     [0., 1., 0.],
                     [0., 0., 1.]]], grad_fn=<ViewBackward0>)
        order)r   r   r   WXYZr"   r   r   r   matrix   s    zQuaternion.matrix)rK   r   c                 C   s   | t |tjdS )ak  Create a quaternion from a rotation matrix.

        Args:
            matrix: the rotation matrix to convert of shape :math:`(B,3,3)`.

        Example:
            >>> m = torch.eye(3)[None]
            >>> q = Quaternion.from_matrix(m)
            >>> q.data
            Parameter containing:
            tensor([[1., 0., 0., 0.]], requires_grad=True)
        rH   )r   r   rJ   )clsrK   r   r   r   from_matrix   s    zQuaternion.from_matrix)
batch_sizer   c                 C   s    t g d}||d}| |S )ao  Create a quaternion representing an identity rotation.

        Args:
            batch_size: the batch size of the underlying data.

        Example:
            >>> q = Quaternion.identity(batch_size=2)
            >>> q.data
            Parameter containing:
            tensor([[1., 0., 0., 0.],
                    [1., 0., 0., 0.]], requires_grad=True)
        )      ?        rP   rP   r:   )r   repeat)rL   rN   r   r   r   r   identity   s    zQuaternion.identity)r9   r>   r@   rB   r   c                 C   s   | t ||||ggS )a  Create a quaternion from the data coefficients.

        Args:
            w: a float representing the :math:`q_w` component.
            x: a float representing the :math:`q_x` component.
            y: a float representing the :math:`q_y` component.
            z: a float representing the :math:`q_z` component.

        Example:
            >>> q = Quaternion.from_coeffs(1., 0., 0., 0.)
            >>> q.data
            Parameter containing:
            tensor([[1., 0., 0., 0.]], requires_grad=True)
        )r   )rL   r9   r>   r@   rB   r   r   r   from_coeffs	  s    zQuaternion.from_coeffsc           	      C   s   t d|\}}}d|  dt |   }d|  dt |   }| dt |   }| dt |   }| t||||fdS )a  Create a random unit quaternion of shape :math:`(B,4)`.

        Uniformly distributed across the rotation space as per: http://planning.cs.uiuc.edu/node198.html

        Args:
            batch_size: the batch size of the underlying data.

        Example:
            >>> q = Quaternion.random(batch_size=2)
            >>> q.norm()
            tensor([1.0000, 1.0000], grad_fn=<NormBackward1>)
        r?   rO   r=   r/   )r
   sqrtr   sincosr   )	rL   rN   Zr1Zr2Zr3Zq1Zq2Zq3Zq4r   r   r   random  s    zQuaternion.randomc                 C   s   | j jdddS )Nr=   r/   )pZdim)r   rE   r"   r   r   r   rE   0  s    zQuaternion.normc                 C   s   t t| jS r$   )r   r   r   r"   r   r   r   	normalize3  s    zQuaternion.normalizec                 C   s   t t| j| j fdS r.   )r   r	   r    r!   r"   r   r   r   conj6  s    zQuaternion.conjc                 C   s   |   |   S r$   )rZ   squared_normr"   r   r   r   r3   9  s    zQuaternion.invc                 C   s   |  | j| jd  S )Nr=   )r0   r!   r    r"   r   r   r   r[   <  s    zQuaternion.squared_normc                 C   sD   |d u r|}t |j|jk |dd d d f |dd d d f  d S )N.).r   )r   rD   )r   r>   r@   r   r   r   r0   ?  s    z Quaternion._batched_squared_normc                 C   s   t d S r$   )NotImplementedErrorr"   r   r   r   slerpF  s    zQuaternion.slerp)N).__name__
__module____qualname____doc__r   r   strr#   r'   r(   r,   r-   r1   r   r4   r5   propertyr   r8   r    r!   r;   r<   r9   r>   r@   rB   r   intrD   rG   rK   classmethodrM   rR   floatrS   rW   rE   rY   rZ   r3   r[   r0   r]   __classcell__r   r   r   r   r      sd   &


r   N)mathr   typingr   r   Zkornia.corer   r   r   r   r	   r
   r   Zkornia.geometry.conversionsr   r   r   r   Zkornia.testingr   r   r   r   r   r   r   r   <module>   s
   $