
    i92i                        S r SSKrSSKrSSKJr  SSKJrJrJr  SS0r	S r
\
S 5       r\\\\R                  4   r\\\R                  4rS@S	 jrS
 r " S S\" SS\4S\4S\4S\\   4/5      5      rS\	S'   S\	S'   S\	S'   S\	S'   S\	S'    " S S\" SS\4S\\   4/5      5      rS\	S'   S\	S'   S\	S'    " S  S!\" S!S"\4S#\4S$\4S%\4S\\   4/5      5      rS\	S&'   S'\	S('   S)\	S*'   S+\	S,'   S-\	S.'   S\	S/'   SAS0 jrSAS1 jrSBS2 jrSAS3 jrS4 rS5 r " S6 S7\5      r " S8 S9\5      rS\	S:'   S\	S;'   S\	S<'   S\	S='   S\	S>'   S\	S?'   g)Ca$  
Core drawing primitives for fpdf2.

This module defines the fundamental data structures used throughout the
drawing API, including:

- Color models: ``DeviceRGB``, ``DeviceGray``, ``DeviceCMYK``
- Geometric primitives: ``Point``
- Transformation matrices: ``Transform``

These classes are intentionally lightweight and self-contained so they can be
safely imported from any other drawing-related module without creating circular
dependencies.

All higher-level drawing features (paths, patterns, gradients, etc.) build on
top of these primitives.
    N)Sequence)
NamedTupleOptionalUnionforce_nodocumentFc                 ,    S[         U R                  '   U $ )zQA decorator that forces pdoc not to document the decorated item (class or method)F__pdoc____qualname__items    Q/home/james-whalen/.local/lib/python3.13/site-packages/fpdf/drawing_primitives.pyr   r      s    "'HTK    c                 ,    S[         U R                  '   U $ )zMA decorator that forces pdoc to document the decorated item (class or method)Tr	   r   s    r   force_documentr   #   s     #'HTKr   c                 J    Xs=::  a  U::  d  O  [        U  SU SU S35      eU $ )Nz not in range [z, ])
ValueError)valueminimummaximums      r   check_ranger   .   s0    &w&E7/'"WIQGHHLr   c                 F    U S R                  S5      R                  S5      $ )z
Convert a decimal number to a minimal string representation (no trailing 0 or .).

Args:
    number (Number): the number to be converted to a string.

Returns:
    The number's string representation.
z.4f0.)rstrip)numbers    r   number_to_strr   5   s$     S\!!#&--c22r   c                   |   ^  \ rS rSrSrSr SU 4S jjr\S 5       r\S 5       r	S\
4S jrS\4S	 jrSS
 jrSrU =r$ )	DeviceRGBK   z+A class representing a PDF DeviceRGB color.rgc                 |   > Ub  [        U5        [        TU ]	  U [        U5      [        U5      [        U5      U5      $ Nr   super__new__)clsrgba	__class__s        r   r'   DeviceRGB.__new__d   s4    =NwsKNKNKPQNTUVVr   c                     U SS $ )zVThe color components as a tuple in order `(r, g, b)` with alpha omitted, in range 0-1.N selfs    r   colorsDeviceRGB.colorsj        CRyr   c                 :    [        S U R                   5       5      $ )XThe color components as a tuple in order `(r, g, b)` with alpha omitted, in range 0-255.c              3   ,   #    U  H
  nS U-  v   M     g7f   Nr1   .0vs     r   	<genexpr>&DeviceRGB.colors255.<locals>.<genexpr>r        2kS1Wk   tupler4   r2   s    r   	colors255DeviceRGB.colors255o        2dkk222r   returnc                 f    SR                  S U R                   5       5      SU R                   3-   $ )N c              3   8   #    U  H  n[        U5      v   M     g 7fr$   r   r=   vals     r   r?   &DeviceRGB.serialize.<locals>.<genexpr>u        Bksc**k   joinr4   OPERATORr2   s    r   	serializeDeviceRGB.serializet   +    xxBdkkBBqEXXXr   c                     [        U R                  U R                  -
  5      S:  =(       a%    [        U R                  U R                  -
  5      S:  $ )Ng&.>)absr)   r*   r+   r2   s    r   is_achromaticDeviceRGB.is_achromaticw   s9    466DFF?#d*Js466DFF?/Cd/JJr   c                 r    [        SU R                  -  SU R                  -  -   SU R                  -  -   5      $ )Ngz6?g,C?g]m{?)
DeviceGrayr)   r*   r+   r2   s    r   to_grayDeviceRGB.to_gray{   s/    &466/FTVVO;ftvvoMNNr   r1   r$   )rH   r]   )__name__
__module__r   __firstlineno____doc__rT   r'   propertyr4   rE   strrU   boolrZ   r^   __static_attributes____classcell__r-   s   @r   r    r    K   sh     6  HFW   3 3Y3 YKt KO Or   r    r)   r*   r+   r,   zDeviceRGB.OPERATORz8The red color component. Must be in the interval [0, 1].zDeviceRGB.rz:The green color component. Must be in the interval [0, 1].zDeviceRGB.gz9The blue color component. Must be in the interval [0, 1].zDeviceRGB.baD  
The alpha color component (i.e. opacity). Must be `None` or in the interval [0, 1].

An alpha value of 0 makes the color fully transparent, and a value of 1 makes it fully
opaque. If `None`, the color will be interpreted as not specifying a particular
transparency rather than specifying fully transparent or fully opaque.
zDeviceRGB.ac                   d   ^  \ rS rSrSrSr S
U 4S jjr\S 5       r\S 5       r	S\
4S jrS	rU =r$ )r]      z,A class representing a PDF DeviceGray color.r*   c                 T   > Ub  [        U5        [        TU ]	  U [        U5      U5      $ r$   r%   )r(   r*   r,   r-   s      r   r'   DeviceGray.__new__   s&    =NwsKNA66r   c                 H    U R                   U R                   U R                   4$ )zTThe color components as a tuple in order (r, g, b) with alpha omitted, in range 0-1.)r*   r2   s    r   r4   DeviceGray.colors   s     vvtvvtvv%%r   c                 :    [        S U R                   5       5      $ )r8   c              3   ,   #    U  H
  nS U-  v   M     g7fr:   r1   r<   s     r   r?   'DeviceGray.colors255.<locals>.<genexpr>   rA   rB   rC   r2   s    r   rE   DeviceGray.colors255   rG   r   rH   c                 J    [        U R                  5       SU R                   3$ )NrJ   )r   r*   rT   r2   s    r   rU   DeviceGray.serialize   s!    '($--99r   r1   r$   )r`   ra   r   rb   rc   rT   r'   rd   r4   rE   re   rU   rg   rh   ri   s   @r   r]   r]      sN     7HF7 & & 3 3:3 : :r   r]   zDeviceGray.OPERATORz}
The gray color component. Must be in the interval [0, 1].

A value of 0 represents black and a value of 1 represents white.
zDeviceGray.gzDeviceGray.ac                   T   ^  \ rS rSrSrSr S	U 4S jjr\S 5       rS\	4S jr
SrU =r$ )

DeviceCMYK   z,A class representing a PDF DeviceCMYK color.kc           	         > Ub  [        U5        [        TU ]	  U [        U5      [        U5      [        U5      [        U5      U5      $ r$   r%   )r(   cmyry   r,   r-   s         r   r'   DeviceCMYK.__new__   s>    =NwQQQQQR
 	
r   c                     U SS $ )zWThe color components as a tuple in order (c, m, y, k) with alpha omitted, in range 0-1.Nr0   r1   r2   s    r   r4   DeviceCMYK.colors   r6   r   rH   c                 f    SR                  S U R                   5       5      SU R                   3-   $ )NrJ   c              3   8   #    U  H  n[        U5      v   M     g 7fr$   rL   rM   s     r   r?   'DeviceCMYK.serialize.<locals>.<genexpr>   rP   rQ   rR   r2   s    r   rU   DeviceCMYK.serialize   rW   r   r1   r$   )r`   ra   r   rb   rc   rT   r'   rd   r4   re   rU   rg   rh   ri   s   @r   rw   rw      s=     7HF
  Y3 Y Yr   rw   r{   r|   r}   ry   zDeviceCMYK.OPERATORz9The cyan color component. Must be in the interval [0, 1].zDeviceCMYK.cz<The magenta color component. Must be in the interval [0, 1].zDeviceCMYK.mz;The yellow color component. Must be in the interval [0, 1].zDeviceCMYK.yz:The black color component. Must be in the interval [0, 1].zDeviceCMYK.kzDeviceCMYK.ac                 |    Uc  Xs=:X  a  U:X  a  O  O[        U S-  5      $ OUS-  n[        U S-  US-  US-  U5      $ )a   
Produce a DeviceRGB color from the given 8-bit RGB values.

Args:
    r (Number): red color component. Must be in the interval [0, 255].
    g (Number): green color component. Must be in the interval [0, 255].
    b (Number): blue color component. Must be in the interval [0, 255].
    a (Optional[Number]): alpha component. Must be `None` or in the interval
        [0, 255]. 0 is fully transparent, 255 is fully opaque

Returns:
    DeviceRGB color representation.

Raises:
    ValueError: if any components are not in their valid interval.
     o@)r]   r    )r)   r*   r+   r,   s       r   rgb8r      sN    " 	y;Q;a%i((  	
U
QYE	1u9a88r   c                 0    Ub  US-  n[        U S-  U5      $ )a  
Produce a DeviceGray color from the given 8-bit gray value.

Args:
    g (Number): gray color component. Must be in the interval [0, 255]. 0 is black,
        255 is white.
    a (Optional[Number]): alpha component. Must be `None` or in the interval
        [0, 255]. 0 is fully transparent, 255 is fully opaque

Returns:
    DeviceGray color representation.

Raises:
    ValueError: if any components are not in their valid interval.
r   )r]   )r*   r,   s     r   gray8r     s#      	}	U
a%i##r   c                 J   [        U [        [        [        45      (       a  U $ [        U [        5      (       a!  U R                  S5      (       a  [        U 5      $ [        U [        5      (       a  U u  pnXU4S:X  d  US:X  a  [        U S-  5      $ [        U S-  US-  US-  5      $ )N#)r   r   r   r0   r;   )
isinstancerw   r]   r    re   
startswithcolor_from_hex_stringr   )r)   r*   r+   s      r   convert_to_device_colorr   )  s    !j*i899!Sall3//$Q''!Xa	ayIb!c'""QWa#gq3w//r   c                 H    Ub  US-  n[        U S-  US-  US-  US-  U5      $ )ak  
Produce a DeviceCMYK color from the given 8-bit CMYK values.

Args:
    c (Number): red color component. Must be in the interval [0, 255].
    m (Number): green color component. Must be in the interval [0, 255].
    y (Number): blue color component. Must be in the interval [0, 255].
    k (Number): blue color component. Must be in the interval [0, 255].
    a (Optional[Number]): alpha component. Must be `None` or in the interval
        [0, 255]. 0 is fully transparent, 255 is fully opaque

Returns:
    DeviceCMYK color representation.

Raises:
    ValueError: if any components are not in their valid interval.
r   )rw   )r{   r|   r}   ry   r,   s        r   cmyk8r   6  s5    $ 	}	U
a%iUAIq5y!DDr   c                    [        U [        5      (       d  [        U  S35      eU R                  S5      (       d  [	        U  S35      e[        U 5      nUS:X  a*  [        U SS  Vs/ s H  n[        US-  SS	9PM     snS
S06$ US:X  a'  [        U SS  Vs/ s H  n[        US-  SS	9PM     sn6 $ US:X  a4  [        [        SUS5       Vs/ s H  n[        XUS-    SS	9PM     snS
S06$ US:X  a1  [        [        SUS5       Vs/ s H  n[        XUS-    SS	9PM     sn6 $ [	        U  S35      es  snf s  snf s  snf s  snf )a  
Parse an RGB color from a css-style 8-bit hexadecimal color string.

Args:
    hexstr (str): of the form `#RGB`, `#RGBA`, `#RRGGBB`, or `#RRGGBBAA` (case
        insensitive). Must include the leading octothorp. Forms omitting the alpha
        field are interpreted as not specifying the opacity, so it will not be
        explicitly set.

        An alpha value of `00` is fully transparent and `FF` is fully opaque.

Returns:
    DeviceRGB representation of the color.
 is not of type strr   z does not start with #      N      )baser,         	   z0 could not be interpreted as a RGB(A) hex string)	r   re   	TypeErrorr   r   lenr   intrange)hexstrhlencharidxs       r   r   r   N  sm    fc""6("5677S!!F8#9:;;v;DqyDc$(,DMMMqyDc$(,DEEqy=B1dA=NO=Ncc&sQw'b1=NO
SW
 	
 qyU1dTUEVWEVcc&sQw/b9EVWXX
xOP
QQ E E P Xs   %D/D4
D9D>c                    [        U [        5      (       d  [        U  S35      eU R                  SS5      n U R	                  S5      (       a  U R                  S5      (       d  [        U  S35      eU SS n U R                  S	5      n[        U5      S
:X  a%  [        U Vs/ s H  n[        U5      PM     snSS06$ [        U5      S:X  a"  [        U Vs/ s H  n[        U5      PM     sn6 $ [        U  S35      es  snf s  snf )z
Parse an RGB color from a css-style rgb(R, G, B, A) color string.

Args:
    rgbstr (str): of the form `rgb(R, G, B)` or `rgb(R, G, B, A)`.

Returns:
    DeviceRGB representation of the color.
r   rJ    zrgb()z- does not follow the expected rgb(...) formatr   r0   ,   r,   Nz6 could not be interpreted as a rgb(R, G, B[, A]) color)r   re   r   replacer   endswithr   splitr   r   r   )rgbstrr4   r{   s      r   color_from_rgb_stringr   v  s     fc""6("5677^^C$FV$$FOOC,@,@F8#PQRRAb\F\\#F
6{af-fc!ff-666
6{af-fc!ff-..
xUV
WW . .s   C9C>c                       \ rS rSr% Sr\\S'    \\S'    S\4S jrSS S\4S jr	SS S\4S	 jr
S\4S
 jr\SS j5       r\SS j5       r\SS j5       r\SS j5       r\r\S\SS 4S j5       r\S\SS 4S j5       r\SS j5       rS\4S jrSrg)Pointi  zE
An x-y coordinate pair within the two-dimensional coordinate frame.
xr}   rH   c                 \    [        U R                  5       S[        U R                  5       3$ )z=Render the point to the string `"x y"` for emitting to a PDF.rJ   r   r   r}   r2   s    r   renderPoint.render  s)      '(-*?)@AAr   otherc                     [        U[        5      (       d  [        SU< 35      eU R                  UR                  -  U R                  UR                  -  -   $ )z
Compute the dot product of two points.

Args:
    other (Point): the point with which to compute the dot product.

Returns:
    The scalar result of the dot product computation.

Raises:
    TypeError: if `other` is not a `Point`.
zcannot dot with )r   r   r   r   r}   r3   r   s     r   dot	Point.dot  sI     %''.ui899vv$&&577"222r   c           	         [        U[        5      (       d  [        SU< 35      eU R                  UR                  -  U R                  UR                  -  -
  nUS:  US:  -
  nU R                  5       UR                  5       -  S:X  a  gU[        R                  " [        U R                  U5      U R                  5       UR                  5       -  -  S5      5      -  $ )a}  
Compute the angle between two points (interpreted as vectors from the origin).

The return value is in the interval (-pi, pi]. Sign is dependent on ordering,
with clockwise angle travel considered to be positive due to the orientation of
the coordinate frame basis vectors (i.e. the angle between `(1, 0)` and `(0, 1)`
is `+pi/2`, the angle between `(1, 0)` and `(0, -1)` is `-pi/2`, and the angle
between `(0, -1)` and `(1, 0)` is `+pi/2`).

Args:
    other (Point): the point to compute the angle sweep toward.

Returns:
    The scalar angle between the two points **in radians**.

Raises:
    TypeError: if `other` is not a `Point`.
zcannot compute angle with r              )
r   r   r   r   r}   magmathacosroundr   )r3   r   	signifiersigns       r   anglePoint.angle  s    ( %''8	BCCVVegg%$&&577*:;	Q9q=188:		#q(diidhhuoeiik9Q&RTU VWWWr   c                 F    U R                   S-  U R                  S-  -   S-  $ )z
Compute the Cartesian distance from this point to the origin

This is the same as computing the magnitude of the vector represented by this
point.

Returns:
    The scalar result of the distance computation.
r   g      ?r   r}   r2   s    r   r   	Point.mag  s$     	DFFAI%#--r   c                     [        U[        5      (       a8  [        U R                  UR                  -   U R                  UR                  -   S9$ [        $ )a.  
Produce the sum of two points.

Adding two points is the same as translating the source point by interpreting
the other point's x and y coordinates as distances.

Args:
    other (Point): right-hand side of the infix addition operation

Returns:
    A Point which is the sum of the two source points.
r   r   r   r   r}   NotImplementedr   s     r   __add__Point.__add__  s>     eU##466EGG+tvv/?@@r   c                     [        U[        5      (       a8  [        U R                  UR                  -
  U R                  UR                  -
  S9$ [        $ )z
Produce the difference between two points.

Unlike addition, this is not a commutative operation!

Args:
    other (Point): right-hand side of the infix subtraction operation

Returns:
    A Point which is the difference of the two source points.
r   r   r   s     r   __sub__Point.__sub__  s>     eU##466EGG+tvv/?@@r   c                 B    [        U R                  * U R                  * S9$ )z
Produce a point by negating this point's coordinates.

Returns:
    A Point whose coordinates are this points coordinates negated.
r   )r   r   r}   r2   s    r   __neg__Point.__neg__  s     w466'**r   c                     [        U[        5      (       a&  [        U R                  U-  U R                  U-  5      $ [
        $ )z
Multiply a point by a scalar value.

Args:
    other (Number): the scalar value by which to multiply the point's
        coordinates.

Returns:
    A Point whose coordinates are the result of the multiplication.
)r   NumberClassr   r   r}   r   r   s     r   __mul__Point.__mul__  s4     e[))%%88r   c                     [        U[        5      (       a8  [        U R                  [	        U5      -  U R
                  [	        U5      -  5      $ [        $ )aV  
Divide a point by a scalar value.

.. note::

    Because division is not commutative, `Point / scalar` is implemented, but
    `scalar / Point` is nonsensical and not implemented.

Args:
    other (Number): the scalar value by which to divide the point's coordinates.

Returns:
    A Point whose coordinates are the result of the division.
r   r   r   r   floatr}   r   r   s     r   __truediv__Point.__truediv__"  s>      e[))%,.u0EFFr   c                     [        U[        5      (       a8  [        U R                  [	        U5      -  U R
                  [	        U5      -  5      $ [        $ )ao  
Divide a point by a scalar value using integer division.

.. note::

    Because division is not commutative, `Point // scalar` is implemented, but
    `scalar // Point` is nonsensical and not implemented.

Args:
    other (Number): the scalar value by which to divide the point's coordinates.

Returns:
    A Point whose coordinates are the result of the division.
r   r   s     r   __floordiv__Point.__floordiv__7  s>      e[))5</5<1GHHr   c                 D   [        U[        5      (       a  [        UR                  U R                  -  UR
                  U R                  -  -   UR                  -   UR                  U R                  -  UR                  U R                  -  -   UR                  -   S9$ [        $ )ad  
Transform a point with the given transform matrix.

.. note::
    This operator is only implemented for Transforms. This transform is not
    commutative, so `Point @ Transform` is implemented, but `Transform @ Point`
    is not implemented (technically speaking, the current implementation is
    commutative because of the way points and transforms are represented, but
    if that representation were to change this operation could stop being
    commutative)

Args:
    other (Transform): the transform to apply to the point

Returns:
    A Point whose coordinates are the result of applying the transform.
r   )r   	Transformr   r,   r   r{   r}   er+   dfr   r   s     r   
__matmul__Point.__matmul__N  s|    & eY''''DFF"UWWtvv%55?''DFF"UWWtvv%55? 
 r   c                 `    S[        U R                  5       S[        U R                  5       S3$ )Nz(x=z, y=r   r   r2   s    r   __str__Point.__str__i  s+    ]466*+4dff0E/FaHHr   r1   N)r   r   rH   r   )rH   r   )r   r   rH   r   )r`   ra   r   rb   rc   r   __annotations__re   r   r   r   r   r   r   r   r   r   __rmul__Numberr   r   r   r   rg   r1   r   r   r   r     s    H$H$B B
3 3U 3$X7 Xu X:.U .  $  " + +    H G  ( & W  ,  4I Ir   r   c                      \ rS rSr% Sr\\S'   \\S'   \\S'   \\S'   \\S'   \\S'   \S-S
 j5       r\S\	S\	S	S 4S j5       r
\S.S\	S\\	   S	S 4S jj5       r\S\	S	S 4S j5       r\S\	S	S 4S j5       r\S.S\	S\\	   S	S 4S jj5       r\S/S\	S\\	   S	S 4S jj5       r\S/S\	S\\	   S	S 4S jj5       rS\	S\	S	S 4S jrS.S\	S\\	   S	S 4S jjrS\	S	S 4S jrS\	S	S 4S jrS.S\	S\\	   S	S 4S jjrS/S\	S\\	   S	S 4S  jjrS/S\	S\\	   S	S 4S! jjrS\	S\	S	S 4S" jrS-S# jr\S$\	S	S 4S% j5       r\r\S0S& j5       rS'S(S	\\ S(4   4S) jr!S	\ 4S* jr"S	\\\4   4S+ jr#S,r$g)1r   im  a  
A representation of an affine transformation matrix for 2D shapes.

The actual matrix is:

```
                    [ a b 0 ]
[x' y' 1] = [x y 1] [ c d 0 ]
                    [ e f 1 ]
```

Complex transformation operations can be composed via a sequence of simple
transformations by performing successive matrix multiplication of the simple
transformations.

For example, scaling a set of points around a specific center point can be
represented by a translation-scale-translation sequence, where the first
translation translates the center to the origin, the scale transform scales the
points relative to the origin, and the second translation translates the points
back to the specified center point. Transform multiplication is performed using
python's dedicated matrix multiplication operator, `@`

The semantics of this representation mean composed transformations are specified
left-to-right in order of application (some other systems provide transposed
representations, in which case the application order is right-to-left).

For example, to rotate the square `(1,1) (1,3) (3,3) (3,1)` 45 degrees clockwise
about its center point (which is `(2,2)`) , the translate-rotate-translate
process described above may be applied:

```python
rotate_centered = (
    Transform.translation(-2, -2)
    @ Transform.rotation_d(45)
    @ Transform.translation(2, 2)
)
```

Instances of this class provide a chaining API, so the above transform could also be
constructed as follows:

```python
rotate_centered = Transform.translation(-2, -2).rotate_d(45).translate(2, 2)
```

Or, because the particular operation of performing some transformations about a
specific point is pretty common,

```python
rotate_centered = Transform.rotation_d(45).about(2, 2)
```

By convention, this class provides class method constructors following noun-ish
naming (`translation`, `scaling`, `rotation`, `shearing`) and instance method
manipulations following verb-ish naming (`translate`, `scale`, `rotate`, `shear`).
r,   r+   r{   r   r   r   rH   c                     U " SSSSSS5      $ )z]
Create a transform representing the identity transform.

The identity transform is a no-op.
r   r   r1   )r(   s    r   identityTransform.identity  s     1aAq!$$r   r   r}   c           
      @    U " SSSS[        U5      [        U5      5      $ )a  
Create a transform that performs translation.

Args:
    x (Number): distance to translate points along the x (horizontal) axis.
    y (Number): distance to translate points along the y (vertical) axis.

Returns:
    A Transform representing the specified translation.
r   r   r   r(   r   r}   s      r   translationTransform.translation  s!     1aAuQxq22r   Nc                 J    Uc  UnU " [        U5      SS[        U5      SS5      $ )a  
Create a transform that performs scaling.

Args:
    x (Number): scaling ratio in the x (horizontal) axis. A value of 1
        results in no scale change in the x axis.
    y (Number): optional scaling ratio in the y (vertical) axis. A value of 1
        results in no scale change in the y axis. If this value is omitted, it
        defaults to the value provided to the `x` argument.

Returns:
    A Transform representing the specified scaling.
r   r   r   s      r   scalingTransform.scaling  s+     9A58Q58Q22r   thetac                     U " [         R                  " U5      [         R                  " U5      [         R                  " U5      * [         R                  " U5      SS5      $ )z
Create a transform that performs rotation.

Args:
    theta (Number): the angle **in radians** by which to rotate. Positive
        values represent clockwise rotations.

Returns:
    A Transform representing the specified rotation.

r   )r   cossin)r(   r   s     r   rotationTransform.rotation  sC     HHUOTXXe_txx.>QRTU
 	
r   theta_dc                 L    U R                  [        R                  " U5      5      $ )z
Create a transform that performs rotation **in degrees**.

Args:
    theta_d (Number): the angle **in degrees** by which to rotate. Positive
        values represent clockwise rotations.

Returns:
    A Transform representing the specified rotation.

)r   r   radians)r(   r   s     r   
rotation_dTransform.rotation_d  s     ||DLL122r   c                 J    Uc  UnU " S[        U5      [        U5      SSS5      $ )aX  
Create a transform that performs shearing (not of sheep).

Args:
    x (Number): The amount to shear along the x (horizontal) axis.
    y (Number): Optional amount to shear along the y (vertical) axis. If omitted,
        this defaults to the value provided to the `x` argument.

Returns:
    A Transform representing the specified shearing.

r   r   r   r   s      r   shearingTransform.shearing  s+     9A1eAha!Q22r   axayc           	          Uc  UnU " S[         R                  " [        U5      5      [         R                  " [        U5      5      SSS5      $ )a  
Create a skew (shear) transform using angles **in radians**.

Args:
    ax (Number): skew angle along the X axis (radians).
        Positive ax produces x' = x + tan(ax) * y
    ay (Number): optional skew angle along the Y axis (radians).
        Positive ay produces y' = y + tan(ay) * x
        If omitted, defaults to the value of `ax`.

Returns:
    A Transform representing the specified skew.
r   r   )r   tanr   )r(   r  r  s      r   skewingTransform.skewing  s=     :B1dhhuRy)488E"I+>1aHHr   ax_day_dc                 P   Uc  Un[         R                  " [        U5      5      n[         R                  " [        U5      5      nSn[        [         R                  " U5      5      U:  d#  [        [         R                  " U5      5      U:  a  [        S5      eU R                  X45      $ )ub  
Create a skew (shear) transform using angles **in degrees**.

Args:
    ax_d (Number): skew angle along X in degrees.
    ay_d (Number): optional skew angle along Y in degrees. If omitted, defaults to ax_d.

Returns:
    A Transform representing the specified skew.

Raises:
    ValueError: if an angle is too close to 90° + k·180° (infinite shear).
g-q=u:   Skew angle produces infinite shear (near 90° + k·180°).)r   r   r   rY   r   r   r
  )r(   r  r  r  r  epss         r   	skewing_dTransform.skewing_d&  s{     <D\\%+&\\%+&txx|s"c$((2,&7#&=YZZ{{2""r   c                 2    U [         R                  X5      -  $ )a  
Produce a transform by composing the current transform with a translation.

.. note::
    Transforms are immutable, so this returns a new transform rather than
    mutating self.

Args:
    x (Number): distance to translate points along the x (horizontal) axis.
    y (Number): distance to translate points along the y (vertical) axis.

Returns:
    A Transform representing the composed transform.
r   r   r3   r   r}   s      r   	translateTransform.translate?  s     i++A111r   c                 2    U [         R                  X5      -  $ )aH  
Produce a transform by composing the current transform with a scaling.

.. note::
    Transforms are immutable, so this returns a new transform rather than
    mutating self.

Args:
    x (Number): scaling ratio in the x (horizontal) axis. A value of 1
        results in no scale change in the x axis.
    y (Number): optional scaling ratio in the y (vertical) axis. A value of 1
        results in no scale change in the y axis. If this value is omitted, it
        defaults to the value provided to the `x` argument.

Returns:
    A Transform representing the composed transform.
)r   r   r  s      r   scaleTransform.scaleP  s    $ i''---r   c                 2    U [         R                  U5      -  $ )ao  
Produce a transform by composing the current transform with a rotation.

.. note::
    Transforms are immutable, so this returns a new transform rather than
    mutating self.

Args:
    theta (Number): the angle **in radians** by which to rotate. Positive
        values represent clockwise rotations.

Returns:
    A Transform representing the composed transform.
)r   r   )r3   r   s     r   rotateTransform.rotated  s     i((///r   c                 2    U [         R                  U5      -  $ )a  
Produce a transform by composing the current transform with a rotation
**in degrees**.

.. note::
    Transforms are immutable, so this returns a new transform rather than
    mutating self.

Args:
    theta_d (Number): the angle **in degrees** by which to rotate. Positive
        values represent clockwise rotations.

Returns:
    A Transform representing the composed transform.
)r   r  )r3   r   s     r   rotate_dTransform.rotate_du  s      i**7333r   c                 2    U [         R                  X5      -  $ )a  
Produce a transform by composing the current transform with a shearing.

.. note::
    Transforms are immutable, so this returns a new transform rather than
    mutating self.

Args:
    x (Number): The amount to shear along the x (horizontal) axis.
    y (Number): Optional amount to shear along the y (vertical) axis. If omitted,
        this defaults to the value provided to the `x` argument.

Returns:
    A Transform representing the composed transform.
)r   r  r  s      r   shearTransform.shear  s      i((...r   c                 2    U [         R                  X5      -  $ )zCompose with a skew (radians).)r   r
  )r3   r  r  s      r   skewTransform.skew  s    i''///r   c                 2    U [         R                  X5      -  $ )zCompose with a skew (degrees).)r   r  )r3   r  r  s      r   skew_dTransform.skew_d  s    i))$555r   c                 d    [         R                  U* U* 5      U -  [         R                  X5      -  $ )aM  
Bracket the given transform in a pair of translations to make it appear about a
point that isn't the origin.

This is a useful shorthand for performing a transform like a rotation around the
center point of an object that isn't centered at the origin.

.. note::
    Transforms are immutable, so this returns a new transform rather than
    mutating self.

Args:
    x (Number): the point along the x (horizontal) axis about which to transform.
    y (Number): the point along the y (vertical) axis about which to transform.

Returns:
    A Transform representing the composed transform.
r  r  s      r   aboutTransform.about  s0    & $$aR!,t3i6K6KA6QQQr   c           
         U R                   U R                  -  U R                  U R                  -  -
  nUS:X  a  [	        S5      e[        U R                  U-  U R                  * U-  U R                  * U-  U R                   U-  U R                  U R                  -  U R                  U R                  -  -
  U-  U R                  U R                  -  U R                   U R                  -  -
  U-  S9$ )z
Produce a transform that is the inverse of this transform.

Returns:
    A Transform representing the inverse of this transform.

Raises:
    ValueError: if the transform is not invertible.
r   zTransform is not invertibler,   r+   r{   r   r   r   )r,   r   r+   r{   r   r   r   r   )r3   dets     r   inverseTransform.inverse  s     fftvvo/!8:;;ffslvvgmvvgmffslvv$&&0C7vv$&&0C7
 	
r   r   c           	         [        U[        5      (       ag  [        U5      n[        U R                  U-  U R
                  U-  U R                  U-  U R                  U-  U R                  U-  U R                  U-  S9$ [        $ )z
Multiply the individual transform parameters by a scalar value.

Args:
    other (Number): the scalar value by which to multiply the parameters

Returns:
    A Transform with the modified parameters.
r-  )r   r   r   r   r,   r+   r{   r   r   r   r   r   s     r   r   Transform.__mul__  sq     e[))%LE&&5.&&5.&&5.&&5.&&5.&&5.  r   c           
         [        U[        5      (       GaT  U R                  U R                  UR                  -  U R                  UR
                  -  -   U R                  UR                  -  U R                  UR                  -  -   U R
                  UR                  -  U R                  UR
                  -  -   U R
                  UR                  -  U R                  UR                  -  -   U R                  UR                  -  U R                  UR
                  -  -   UR                  -   U R                  UR                  -  U R                  UR                  -  -   UR                  -   S9$ [        $ )z
Compose two transforms into a single transform.

Args:
    other (Transform): the right-hand side transform of the infix operator.

Returns:
    A Transform representing the composed transform.
r-  )
r   r   r-   r,   r+   r{   r   r   r   r   r   s     r   r   Transform.__matmul__  s    eY''>>&&577"TVVegg%55&&577"TVVegg%55&&577"TVVegg%55&&577"TVVegg%55&&577"TVVegg%55?&&577"TVVegg%55? "   r   	last_item
Renderablec                    [        U R                  5       S[        U R                  5       S[        U R                  5       S[        U R                  5       S[        U R
                  5       S[        U R                  5       S3U4$ )z
Render the transform to its PDF output representation.

Args:
    last_item: the last path element this transform applies to

Returns:
    A tuple of `(str, last_item)`. `last_item` is returned unchanged.
rJ   z cmr   r,   r+   r{   r   r   r   )r3   r5  s     r   r   Transform.render  s|     TVV$%Q}TVV'<&=QTVV$%Q}TVV'<&=QTVV$%Q}TVV'<&=SB 	
 	
r   c                    S[        U R                  5       S[        U R                  5       S[        U R                  5       S[        U R                  5       S[        U R
                  5       S[        U R                  5       S3$ )Nztransform: [rJ   z 0; z 1]r8  r2   s    r   r   Transform.__str__  ss    TVV$%Q}TVV'<&=TTVV$%Q}TVV'<&=TTVV$%Q}TVV'<&=SB	
r   c                     [         R                  " U R                  U R                  5      [         R                  " U R                  U R
                  5      4$ )u%  
Returns (sqrt(a² + c²), sqrt(b² + d²)), i.e. the Euclidean norms of
those rows. These values bound how much the transform can stretch geometry along the
device X and Y axes, respectively, and are useful for inflating axis-aligned
bounding boxes to account for stroke width under the CTM.
)r   hypotr,   r{   r+   r   r2   s    r   	row_normsTransform.row_norms  s5     

466466*DJJtvvtvv,FGGr   r1   )rH   r   r$   )r   N)r   r   rH   r   )%r`   ra   r   rb   rc   r   r   classmethodr   r   r   r   r   r   r  r  r
  r  r  r  r  r  r!  r$  r'  r*  r/  r   r   r   r   rD   re   r   r   r>  rg   r1   r   r   r   r   m  s   7r HHHHHH % % 3F 3v 3+ 3 3 3 38F#3 3{ 3 3& 
V 
 
 
  3 3K 3 3 3 3HV$4 3 3 3" I I&)9 I[ I I$ #V #x/? #; # #026 2f 2 2".v .(6"2 .k .(0F 0{ 0"4 4; 4$/v /(6"2 /k /$0v 0x'7 0; 066 6Xf-= 6 6Rv R& R[ R*
. V   0 H ,
 
sL7H1I 
"
 
H5. Hr   r   zTransform.azTransform.bzTransform.czTransform.dzTransform.ezTransform.f)r   g      ?r$   )r0   r0   )rc   decimalr   collections.abcr   typingr   r   r   r
   r   r   r   r   Decimalr   r   r   r   r    r]   rw   r   r   r   r   r   r   r   r   r1   r   r   <module>rE     sY  $   % . .&   
sE7??*	+E7??+3,2O
vfV}sHV<L6MN2Oj "'	 T V U  	:
vhv./0:> #(	  	 	Y&M&M&M&M(6"#	
	YD #(	 V B 	  Y W  	94$,
0E0%RPX<VIJ VIrrH
 rHj        r   