
    <`h!                         d Z ddlmZ g dZdZdez
  Zdez   Zd Z G d d	e          Z e            Z	dd
Z
ddZedk    r,ddlZddlZ ej         ej                    j                   dS dS )a  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

Examples:

	>>> 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)]
	>>>
    )
NamedTuple)	TransformIdentityOffsetScalegV瞯<   c                 r    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)vs    8lib/python3.11/site-packages/fontTools/misc/transform.py_normSinCosr   ;   sB    FFX!!,!!
!	    c                       e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	eed<   dZ
eed<   dZeed	<   d
 Zd ZddZddZd ZddZd Zd Zd Zd Zd Zd ZdS )r   aw  2x2 transformation matrix plus offset, a.k.a. Affine transform.
	Transform instances are immutable: all transforming methods, eg.
	rotate(), return a new Transform instance.

	Examples:
		>>> 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   xxr   xyyxyydxdyc                 V    |\  }}| \  }}}}}}	||z  ||z  z   |z   ||z  ||z  z   |	z   fS )zTransform a point.

		Example:
			>>> t = Transform()
			>>> t = t.scale(2.5, 5.5)
			>>> t.transformPoint((100, 100))
			(250.0, 550.0)
		 )
selfpxyr   r   r   r   r   r   s
             r   transformPointzTransform.transformPoint   sL     &1a"b"b"b
Q$A+
BqD2a4K",	--r   c                 F    | \  f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                 N    g | ]!\  }}|z  |z  z   z   |z  |z  z   z   f"S r   r   )	.0r   r   r   r   r   r   r   r   s	      r   
<listcomp>z-Transform.transformPoints.<locals>.<listcomp>   sD    	B	B	B41a2a4"Q$;RTBqD[2-
.	B	B	Br   r   )r   pointsr   r   r   r   r   r   s     @@@@@@r   transformPointszTransform.transformPoints   sE      "b"b"b	B	B	B	B	B	B	B	B	B6	B	B	BBr   c                 8    |                      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   s      r   	translatezTransform.translate   s#     
Aq!Q*	+	++r   Nc                 @    ||}|                      |dd|ddf          S )a
  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*   s      r   scalezTransform.scale   s-     Y1	Aq!Q*	+	++r   c                     ddl }t          |                    |                    }t          |                    |                    }|                     ||| |ddf          S )zReturn 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   N)mathr   cossinr)   )r   angler/   css        r   rotatezTransform.rotate   s\     +++$((5//""!$((5//""!	Ar1a+	,	,,r   c                     ddl }|                     d|                    |          |                    |          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   Nr   )r/   r)   tan)r   r   r   r/   s       r   skewzTransform.skew   s@     +++	DHHQKK!aA>	?	??r   c           
          |\  }}}}}}| \  }}	}
}}}|                      ||z  ||
z  z   ||	z  ||z  z   ||z  ||
z  z   ||	z  ||z  z   ||z  |
|z  z   |z   |	|z  ||z  z   |z             S )zReturn 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dy2s                 r   r)   zTransform.transform   s     "'#sCc3!%#sCc3	Gc#gGc#gGc#gGc#gGc#gGc#g
 
 r   c           
          | \  }}}}}}|\  }}	}
}}}|                      ||z  ||
z  z   ||	z  ||z  z   ||z  ||
z  z   ||	z  ||z  z   ||z  |
|z  z   |z   |	|z  ||z  z   |z             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<   s                 r   reverseTransformzTransform.reverseTransform   s     "&#sCc3!&#sCc3	Gc#gGc#gGc#gGc#gGc#gGc#g
 
 r   c                     | t           k    r| S | \  }}}}}}||z  ||z  z
  }||z  | |z  | |z  ||z  f\  }}}}| |z  ||z  z
  | |z  ||z  z
  }}|                     ||||||          S )zReturn 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   dets           r   inversezTransform.inverse  s     
X
;"b"b"b
22#c6B3s7RCGRV3."b"b3r6BrE>B3r6BrE>b"	BBB	/	//r   c                     d| z  S )zReturn a PostScript representation:
			>>> 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   s    r   toPSzTransform.toPS$  s     
	%%r   c                     | t           k    S )a  Returns True if transform is not identity, False otherwise.
			>>> 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   rP   s    r   __bool__zTransform.__bool__-  s    " 
	r   c                 (    d| j         j        f| z   z  S )Nz<%s [%g %g %g %g %g %g]>)r;   __name__rP   s    r   __repr__zTransform.__repr__@  s    	#(?'AD'H	IIr   r   r   )r   N)rU   
__module____qualname____doc__r   float__annotations__r   r   r   r   r   r    r&   r+   r-   r5   r8   r)   rK   rN   rQ   rS   rV   r   r   r   r   r   E   sB        E EN UUUUUU. . .
C 
C 
C	, 	, 	, 	,, , , , - - -@ @ @ @  (  .0 0 0(& & &  &J J J J Jr   r   c                 *    t          dddd| |          S )ztReturn the identity transformation offset by x, y.

	Example:
		>>> Offset(2, 3)
		<Transform [1 0 0 1 2 3]>
		>>>
	r   r   r   r   r   s     r   r   r   F  s     	!Q1a###r   Nc                 2    || }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   r^   r_   s     r   r   r   P  s&     I!!Q1a###r   __main__rW   )N)rZ   typingr   __all__r   r   r   r   r   r   r   r   rU   sysdoctestexittestmodfailedr   r   r   <module>ri      s  - -^       7
6
6 8|(] 
 
 
|J |J |J |J |J
 |J |J |J~ 9;;$ $ $ $$ $ $ $ z	/'/


"##### r   