U
    #vh=                     @  s   d Z ddlmZ ddlZddlmZ ddlmZ dddd	d
gZdZ	de	 Z
de	 ZdddddZG dd deZe ZdddddddZddddddd	ZeG dd
 d
ZedkrddlZddlZee j dS )a7  Affine 2D transformation matrix class.

The Transform class implements various transformation matrix operations,
both on the matrix itself, as well as on 2D coordinates.

Transform instances are effectively immutable: all methods that operate on the
transformation itself always return a new instance. This has as the
interesting side effect that Transform instances are hashable, ie. they can be
used as dictionary keys.

This module exports the following symbols:

Transform
	this is the main class
Identity
	Transform instance set to the identity transformation
Offset
	Convenience function that returns a translating transformation
Scale
	Convenience function that returns a scaling transformation

The DecomposedTransform class implements a transformation with separate
translate, rotation, scale, skew, and transformation-center components.

:Example:

	>>> t = Transform(2, 0, 0, 3, 0, 0)
	>>> t.transformPoint((100, 100))
	(200, 300)
	>>> t = Scale(2, 3)
	>>> t.transformPoint((100, 100))
	(200, 300)
	>>> t.transformPoint((0, 0))
	(0, 0)
	>>> t = Offset(2, 3)
	>>> t.transformPoint((100, 100))
	(102, 103)
	>>> t.transformPoint((0, 0))
	(2, 3)
	>>> t2 = t.scale(0.5)
	>>> t2.transformPoint((100, 100))
	(52.0, 53.0)
	>>> import math
	>>> t3 = t2.rotate(math.pi / 2)
	>>> t3.transformPoint((0, 0))
	(2.0, 3.0)
	>>> t3.transformPoint((100, 100))
	(-48.0, 53.0)
	>>> t = Identity.scale(0.5).translate(100, 200).skew(0.1, 0.2)
	>>> t.transformPoints([(0, 0), (1, 1), (100, 100)])
	[(50.0, 100.0), (50.550167336042726, 100.60135501775433), (105.01673360427253, 160.13550177543362)]
	>>>
    )annotationsN)
NamedTuple)	dataclass	TransformIdentityOffsetScaleDecomposedTransformgV瞯<   float)vreturnc                 C  s0   t | tk rd} n| tkr d} n| tk r,d} | S )Nr   r
   r   )abs_EPSILON_ONE_EPSILON_MINUS_ONE_EPSILON)r    r   </tmp/pip-unpacked-wheel-1ufboor8/fontTools/misc/transform.py_normSinCosF   s    r   c                   @  s  e Zd ZU dZdZded< dZded< dZded< dZded< dZ	ded	< dZ
ded
< dd Zdd Zdd Zdd Zd1dddddZd2dddddZddddZd3dddddZdd  Zd!d" Zd#d$ Zd%d&d'd(Zd)d&d*d+Zd,d&d-d.Zd%d&d/d0ZdS )4r   a	  2x2 transformation matrix plus offset, a.k.a. Affine transform.
    Transform instances are immutable: all transforming methods, eg.
    rotate(), return a new Transform instance.

    :Example:

            >>> t = Transform()
            >>> t
            <Transform [1 0 0 1 0 0]>
            >>> t.scale(2)
            <Transform [2 0 0 2 0 0]>
            >>> t.scale(2.5, 5.5)
            <Transform [2.5 0 0 5.5 0 0]>
            >>>
            >>> t.scale(2, 3).transformPoint((100, 100))
            (200, 300)

    Transform's constructor takes six arguments, all of which are
    optional, and can be used as keyword arguments::

            >>> Transform(12)
            <Transform [12 0 0 1 0 0]>
            >>> Transform(dx=12)
            <Transform [1 0 0 1 12 0]>
            >>> Transform(yx=12)
            <Transform [1 0 12 1 0 0]>

    Transform instances also behave like sequences of length 6::

            >>> len(Identity)
            6
            >>> list(Identity)
            [1, 0, 0, 1, 0, 0]
            >>> tuple(Identity)
            (1, 0, 0, 1, 0, 0)

    Transform instances are comparable::

            >>> t1 = Identity.scale(2, 3).translate(4, 6)
            >>> t2 = Identity.translate(8, 18).scale(2, 3)
            >>> t1 == t2
            1

    But beware of floating point rounding errors::

            >>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
            >>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
            >>> t1
            <Transform [0.2 0 0 0.3 0.08 0.18]>
            >>> t2
            <Transform [0.2 0 0 0.3 0.08 0.18]>
            >>> t1 == t2
            0

    Transform instances are hashable, meaning you can use them as
    keys in dictionaries::

            >>> d = {Scale(12, 13): None}
            >>> d
            {<Transform [12 0 0 13 0 0]>: None}

    But again, beware of floating point rounding errors::

            >>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
            >>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
            >>> t1
            <Transform [0.2 0 0 0.3 0.08 0.18]>
            >>> t2
            <Transform [0.2 0 0 0.3 0.08 0.18]>
            >>> d = {t1: None}
            >>> d
            {<Transform [0.2 0 0 0.3 0.08 0.18]>: None}
            >>> d[t2]
            Traceback (most recent call last):
              File "<stdin>", line 1, in ?
            KeyError: <Transform [0.2 0 0 0.3 0.08 0.18]>
    r
   r   xxr   xyyxyydxdyc           
      C  s@   |\}}| \}}}}}}	|| ||  | || ||  |	 fS )zTransform a point.

        :Example:

                >>> t = Transform()
                >>> t = t.scale(2.5, 5.5)
                >>> t.transformPoint((100, 100))
                (250.0, 550.0)
        r   )
selfpxyr   r   r   r   r   r   r   r   r   transformPoint   s    
zTransform.transformPointc                   s,   | \  fdd|D S )zTransform a list of points.

        :Example:

                >>> t = Scale(2, 3)
                >>> t.transformPoints([(0, 0), (0, 100), (100, 100), (100, 0)])
                [(0, 0), (0, 300), (200, 300), (200, 0)]
                >>>
        c                   s8   g | ]0\}}| |    | |   fqS r   r   ).0r   r   r   r   r   r   r   r   r   r   
<listcomp>   s     z-Transform.transformPoints.<locals>.<listcomp>r   )r   Zpointsr   r"   r   transformPoints   s    
zTransform.transformPointsc                 C  s<   |\}}| dd \}}}}|| ||  || ||  fS )zTransform an (dx, dy) vector, treating translation as zero.

        :Example:

                >>> t = Transform(2, 0, 0, 2, 10, 20)
                >>> t.transformVector((3, -4))
                (6, -8)
                >>>
        N   r   )r   r   r   r   r   r   r   r   r   r   r   transformVector   s    
zTransform.transformVectorc                   s,   | dd \  fdd|D S )a  Transform a list of (dx, dy) vector, treating translation as zero.

        :Example:
                >>> t = Transform(2, 0, 0, 2, 10, 20)
                >>> t.transformVectors([(3, -4), (5, -6)])
                [(6, -8), (10, -12)]
                >>>
        Nr%   c                   s0   g | ](\}} | |  | |  fqS r   r   )r!   r   r   r   r   r   r   r   r   r#      s     z.Transform.transformVectors.<locals>.<listcomp>r   )r   Zvectorsr   r'   r   transformVectors   s    	zTransform.transformVectorsr   r   c                 C  s   |  dddd||fS )zReturn a new transformation, translated (offset) by x, y.

        :Example:
                >>> t = Transform()
                >>> t.translate(20, 30)
                <Transform [1 0 0 1 20 30]>
                >>>
        r
   r   	transformr   r   r   r   r   r   	translate   s    	zTransform.translateNfloat | Nonec                 C  s"   |dkr|}|  |dd|ddfS )ak  Return a new transformation, scaled by x, y. The 'y' argument
        may be None, which implies to use the x value for y as well.

        :Example:
                >>> t = Transform()
                >>> t.scale(5)
                <Transform [5 0 0 5 0 0]>
                >>> t.scale(5, 6)
                <Transform [5 0 0 6 0 0]>
                >>>
        Nr   r*   r,   r   r   r   scale   s    zTransform.scale)anglec                 C  s4   t t|}t t|}| ||| |ddfS )a  Return a new transformation, rotated by 'angle' (radians).

        :Example:
                >>> import math
                >>> t = Transform()
                >>> t.rotate(math.pi / 2)
                <Transform [0 1 -1 0 0 0]>
                >>>
        r   )r   mathcossinr+   )r   r0   csr   r   r   rotate   s    
zTransform.rotatec                 C  s"   |  dt|t|dddfS )zReturn a new transformation, skewed by x and y.

        :Example:
                >>> import math
                >>> t = Transform()
                >>> t.skew(math.pi / 4)
                <Transform [1 0 1 1 0 0]>
                >>>
        r
   r   )r+   r1   tanr,   r   r   r   skew  s    
zTransform.skewc              
   C  s   |\}}}}}}| \}}	}
}}}|  || ||
  ||	 ||  || ||
  ||	 ||  || |
|  | |	| ||  | S )a  Return a new transformation, transformed by another
        transformation.

        :Example:
                >>> t = Transform(2, 0, 0, 3, 1, 6)
                >>> t.transform((4, 3, 2, 1, 5, 6))
                <Transform [8 9 4 3 11 24]>
                >>>
        	__class__r   otherZxx1Zxy1Zyx1Zyy1Zdx1Zdy1Zxx2Zxy2Zyx2Zyy2Zdx2Zdy2r   r   r   r+     s    
zTransform.transformc              
   C  s   | \}}}}}}|\}}	}
}}}|  || ||
  ||	 ||  || ||
  ||	 ||  || |
|  | |	| ||  | S )a  Return a new transformation, which is the other transformation
        transformed by self. self.reverseTransform(other) is equivalent to
        other.transform(self).

        :Example:
                >>> t = Transform(2, 0, 0, 3, 1, 6)
                >>> t.reverseTransform((4, 3, 2, 1, 5, 6))
                <Transform [8 6 6 3 21 15]>
                >>> Transform(4, 3, 2, 1, 5, 6).transform((2, 0, 0, 3, 1, 6))
                <Transform [8 6 6 3 21 15]>
                >>>
        r9   r;   r   r   r   reverseTransform%  s    zTransform.reverseTransformc                 C  s   | t kr| S | \}}}}}}|| ||  }|| | | | | || f\}}}}| | ||  | | ||   }}| ||||||S )aK  Return the inverse transformation.

        :Example:
                >>> t = Identity.translate(2, 3).scale(4, 5)
                >>> t.transformPoint((10, 20))
                (42, 103)
                >>> it = t.inverse()
                >>> it.transformPoint((42, 103))
                (10.0, 20.0)
                >>>
        )r   r:   )r   r   r   r   r   r   r   Zdetr   r   r   inverse=  s    (&zTransform.inversestrr   c                 C  s   d|  S )zReturn a PostScript representation

        :Example:

                >>> t = Identity.scale(2, 3).translate(4, 5)
                >>> t.toPS()
                '[2 0 0 3 8 15]'
                >>>
        z[%s %s %s %s %s %s]r   r   r   r   r   toPSQ  s    
zTransform.toPSz'DecomposedTransform'c                 C  s
   t | S )z%Decompose into a DecomposedTransform.)r	   fromTransformrA   r   r   r   toDecomposed]  s    zTransform.toDecomposedboolc                 C  s   | t kS )a  Returns True if transform is not identity, False otherwise.

        :Example:

                >>> bool(Identity)
                False
                >>> bool(Transform())
                False
                >>> bool(Scale(1.))
                False
                >>> bool(Scale(2))
                True
                >>> bool(Offset())
                False
                >>> bool(Offset(0))
                False
                >>> bool(Offset(2))
                True
        )r   rA   r   r   r   __bool__a  s    zTransform.__bool__c                 C  s   d| j jf|   S )Nz<%s [%g %g %g %g %g %g]>)r:   __name__rA   r   r   r   __repr__w  s    zTransform.__repr__)r   r   )r
   N)r   r   )rG   
__module____qualname____doc__r   __annotations__r   r   r   r   r   r    r$   r&   r(   r-   r/   r6   r8   r+   r=   r>   rB   rD   rF   rH   r   r   r   r   r   P   s,   
N)r   r   r   c                 C  s   t dddd| |S )zReturn the identity transformation offset by x, y.

    :Example:
            >>> Offset(2, 3)
            <Transform [1 0 0 1 2 3]>
            >>>
    r
   r   r   r)   r   r   r   r   ~  s    r.   c                 C  s   |dkr| }t | dd|ddS )zReturn the identity transformation scaled by x, y. The 'y' argument
    may be None, which implies to use the x value for y as well.

    :Example:
            >>> Scale(2, 3)
            <Transform [2 0 0 3 0 0]>
            >>>
    Nr   rM   r)   r   r   r   r     s    	c                   @  s   e Zd ZU dZdZded< dZded< dZded< dZded< dZ	ded	< dZ
ded
< dZded< dZded< dZded< dd Zedd ZddddZdS )r	   zThe DecomposedTransform class implements a transformation with separate
    translate, rotation, scale, skew, and transformation-center components.
    r   r   
translateX
translateYrotationr
   scaleXscaleYskewXskewYtCenterXtCenterYc                 C  sZ   | j dkpX| jdkpX| jdkpX| jdkpX| jdkpX| jdkpX| jdkpX| jdkpX| jdkS )Nr   r
   )	rN   rO   rP   rQ   rR   rS   rT   rU   rV   rA   r   r   r   rF     s"    
zDecomposedTransform.__bool__c              
   C  sf  |\}}}}}}t d|}|dk r4||9 }||9 }|| ||  }	d}
d }}d}|dksd|dkrt || ||  }|dkrt || nt ||  }
||	|  }}t || ||  ||  }nl|dks|dkr:t || ||  }t jd |dkrt | | nt ||   }
|	| | }}n t||t |
|| |t || ddd	S )au  Return a DecomposedTransform() equivalent of this transformation.
        The returned solution always has skewY = 0, and angle in the (-180, 180].

        :Example:
                >>> DecomposedTransform.fromTransform(Transform(3, 0, 0, 2, 0, 0))
                DecomposedTransform(translateX=0, translateY=0, rotation=0.0, scaleX=3.0, scaleY=2.0, skewX=0.0, skewY=0.0, tCenterX=0, tCenterY=0)
                >>> DecomposedTransform.fromTransform(Transform(0, 0, 0, 1, 0, 0))
                DecomposedTransform(translateX=0, translateY=0, rotation=0.0, scaleX=0.0, scaleY=1.0, skewX=0.0, skewY=0.0, tCenterX=0, tCenterY=0)
                >>> DecomposedTransform.fromTransform(Transform(0, 0, 1, 1, 0, 0))
                DecomposedTransform(translateX=0, translateY=0, rotation=-45.0, scaleX=0.0, scaleY=1.4142135623730951, skewX=0.0, skewY=0.0, tCenterX=0, tCenterY=0)
        r
   r      g        )r1   copysignsqrtacosatanpir	   degrees)r   r+   abr4   dr   r   ZsxdeltarP   rQ   rR   rS   rr5   r   r   r   rC     s>    & (z!DecomposedTransform.fromTransformr   r@   c                 C  sx   t  }|| j| j | j| j }|t| j	}|
| j| j}|t| jt| j}|| j | j }|S )zReturn the Transform() equivalent of this transformation.

        :Example:
                >>> DecomposedTransform(scaleX=2, scaleY=2).toTransform()
                <Transform [2 0 0 2 0 0]>
                >>>
        )r   r-   rN   rU   rO   rV   r6   r1   radiansrP   r/   rQ   rR   r8   rS   rT   )r   tr   r   r   toTransform  s    
 
zDecomposedTransform.toTransformN)rG   rI   rJ   rK   rN   rL   rO   rP   rQ   rR   rS   rT   rU   rV   rF   classmethodrC   re   r   r   r   r   r	     s   

8__main__)r   r   )N)rK   
__future__r   r1   typingr   dataclassesr   __all__r   r   r   r   r   r   r   r   r	   rG   sysdoctestexittestmodfailedr   r   r   r   <module>   s*   6
  -h