o
    ¼Çh¶=  ã                   @  sÆ   d Z ddlmZ ddlZddlmZ ddlmZ g d¢ZdZ	de	 Z
d	e	 Zddd„ZG dd„ deƒZeƒ Zdddd„Zdddd„ZeG dd„ dƒƒZedkraddlZddlZe e ¡ j¡ dS 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çž¯Ò<é   éÿÿÿÿÚvÚfloatÚreturnc                 C  s4   t | ƒtk r
d} | S | tkrd} | S | tk rd} | S )Nr   r
   r   )ÚabsÚ_EPSILONÚ_ONE_EPSILONÚ_MINUS_ONE_EPSILON)r   © r   úl/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/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d2d3dd„Zd4d5dd„Zd6dd„Zd2d3dd„Zd d!„ Zd"d#„ Zd$d%„ Zd7d(d)„Zd8d+d,„Zd9d.d/„Zd7d0d1„ZdS ):r   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 )zÍTransform 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 )zùTransform 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 | ]\}}ˆ| ˆ|  ˆ  ˆ| ˆ|  ˆ f‘qS r   r   )Ú.0r   r   ©r   r   r   r   r   r   r   r   Ú
<listcomp>¿   s   8 z-Transform.transformPoints.<locals>.<listcomp>r   )r   Úpointsr   r"   r   ÚtransformPoints´   s   
zTransform.transformPointsc                 C  s<   |\}}| dd… \}}}}|| ||  || ||  fS )zéTransform 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   0 z.Transform.transformVectors.<locals>.<listcomp>r   )r   Úvectorsr   r(   r   ÚtransformVectorsÏ   s   	zTransform.transformVectorsr   r   c                 C  s   |   dddd||f¡S )záReturn 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u 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   r1   ÚcÚsr   r   r   Úrotateö   s   
zTransform.rotatec                 C  s"   |   dt |¡t |¡dddf¡S )zõReturn 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,   r2   Ú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   ÚotherÚxx1Úxy1Úyx1Úyy1Údx1Údy1Úxx2Úxy2Úyx2Úyy2Údx2Ú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]>
                >>>
        r:   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   Údetr   r   r   Úinverse=  s   (&zTransform.inverser   Ústrc                 C  s   d|  S )zÎReturn 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.toPSú'DecomposedTransform'c                 C  s
   t  | ¡S )z%Decompose into a DecomposedTransform.)r	   ÚfromTransformrN   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   rN   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__rN   r   r   r   Ú__repr__w  s   zTransform.__repr__©r   r   )r   r   r   r   )r
   N)r   r   r   r/   )r1   r   )r   rM   )r   rP   )r   rS   )rU   Ú
__module__Ú__qualname__Ú__doc__r   Ú__annotations__r   r   r   r   r   r    r%   r'   r*   r.   r0   r7   r9   r,   rJ   rL   rO   rR   rT   rV   r   r   r   r   r   P   s.   
 N



r   r   r   c                 C  s   t dddd| |ƒS )z™Return 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   r   ~  s   r   r/   c                 C  s   |du r| }t | dd|ddƒS )zêReturn 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   r\   r]   r   r   r   r   ‰  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Zded< dZded< dZded< dd„ Zedd„ ƒZddd„ZdS )r	   z˜The 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p,| jdkp,| jdkp,| jdkp,| jdkp,| jdkp,| jdkp,| jdkp,| jdkS )Nr   r
   )	r^   r_   r`   ra   rb   rc   rd   re   rf   rN   r   r   r   rT   §  s"   
ÿþýüûúù÷zDecomposedTransform.__bool__c              
   C  sd  |\}}}}}}t  d|¡}|dk r||9 }||9 }|| ||  }	d}
d }}d}|dks2|dkrgt  || ||  ¡}|dkrHt  || ¡nt  || ¡ }
||	| }}t  || ||  ||  ¡}n5|dkso|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        )r2   ÚcopysignÚsqrtÚacosÚatanÚpir	   Údegrees)r   r,   ÚaÚbr5   Údr   r   ÚsxÚdeltar`   ra   rb   rc   Úrr6   r   r   r   rQ   ´  s@   & &ÿ÷z!DecomposedTransform.fromTransformr   r   c                 C  sx   t ƒ }| | j| j | j| j ¡}| t | j	¡¡}| 
| j| j¡}| t | j¡t | j¡¡}| | j | j ¡}|S )zÝReturn the Transform() equivalent of this transformation.

        :Example:
                >>> DecomposedTransform(scaleX=2, scaleY=2).toTransform()
                <Transform [2 0 0 2 0 0]>
                >>>
        )r   r.   r^   re   r_   rf   r7   r2   Úradiansr`   r0   ra   rb   r9   rc   rd   )r   Útr   r   r   ÚtoTransformí  s   ÿzDecomposedTransform.toTransformN)r   r   )rU   rX   rY   rZ   r^   r[   r_   r`   ra   rb   rc   rd   re   rf   rT   ÚclassmethodrQ   rv   r   r   r   r   r	   —  s   
 
8r	   Ú__main__)r   r   r   r   rW   )r   r   r   r   r   r   )N)r   r   r   r/   r   r   )rZ   Ú
__future__r   r2   Útypingr   Údataclassesr   Ú__all__r   r   r   r   r   r   r   r   r	   rU   ÚsysÚdoctestÚexitÚtestmodÚfailedr   r   r   r   Ú<module>   s.    6

  -hü