U
    td^                     @   s   d Z ddlmZ ddlmZmZmZmZ ddlm	Z	 ddl
mZ dZG dd dZG d	d
 d
eZG dd dZG dd de	ddefdefgZdd Zdd Zdd Zdd Zd$ddZd%ddZd&d!d"Zd#S )'z'
Utility classes for drawing routines.
    )defaultdict)atan2coshypotsin)
NamedTuple)consecutive_pairs)
BoundingBoxPoint	Rectanglecalculate_corner_radiieuclidean_distanceevaluate_cubic_bezier)get_bezier_control_points_for_curved_edge!intersect_bezier_curve_and_circlestr_to_orientation	autocurvec                   @   s  e Zd ZdZdZdd Zedd Zejdd Zedd	 Z	e	jd
d	 Z	edd Z
e
jdd Z
edd Zejdd Zedd Zejdd Zedd Zejdd Zedd Zejdd Zedd Zejdd Zedd Zejdd Zed d! Zejd"d! Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, ZeZd-d. Zd/d0 ZeZd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Z d=S )>r   zClass representing a rectangle._left_top_right_bottomc                 G   s  d}t |dkr~t|d tr*|d j}qt |d dkrPt|d dd }qt |d dkrdd|d d |d d f}n6t |dkrt|}n t |dkrdd|d |d f}|dkrtdztdd |D }W n tk
r   td	Y nX || _dS )
a>  Creates a rectangle.

        The corners of the rectangle can be specified by either a tuple
        (four items, two for each corner, respectively), four separate numbers
        (X and Y coordinates for each corner) or two separate numbers (width
        and height, the upper left corner is assumed to be at (0,0))N   r         zinvalid coordinate formatc                 s   s   | ]}t |V  qd S Nfloat).0Zcoord r   M/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/igraph/drawing/utils.py	<genexpr>7   s     z%Rectangle.__init__.<locals>.<genexpr>z+invalid coordinate format, numbers expected)len
isinstancer   coordstuple
ValueError)selfargsr$   r   r   r    __init__    s&    
zRectangle.__init__c                 C   s   | j | j| j| jfS )zThe coordinates of the corners.

        The coordinates are returned as a 4-tuple in the following order:
        left edge, top edge, right edge, bottom edge.
        r   r'   r   r   r    r$   =   s    zRectangle.coordsc                 C   sT   |\| _ | _| _| _| j | jkr2| j| j  | _ | _| j| jkrP| j| j | _| _dS )zsSets the coordinates of the corners.

        @param coords: a 4-tuple with the coordinates of the corners
        Nr   )r'   r$   r   r   r    r$   F   s
    c                 C   s   | j | j S )zThe width of the rectangle)r   r   r*   r   r   r    widthR   s    zRectangle.widthc                 C   s   | j | | _dS )z<Sets the width of the rectangle by adjusting the right edge.Nr   r   r'   valuer   r   r    r+   W   s    c                 C   s   | j | j S )zThe height of the rectangle)r   r   r*   r   r   r    height\   s    zRectangle.heightc                 C   s   | j | | _dS )z>Sets the height of the rectangle by adjusting the bottom edge.Nr   r   r-   r   r   r    r/   a   s    c                 C   s   | j S )z,The X coordinate of the left side of the box)r   r*   r   r   r    leftf   s    zRectangle.leftc                 C   s   t || _t| j| j| _dS )z1Sets the X coordinate of the left side of the boxN)r   r   maxr   r-   r   r   r    r1   k   s    
c                 C   s   | j S )z-The X coordinate of the right side of the box)r   r*   r   r   r    rightq   s    zRectangle.rightc                 C   s   t || _t| j| j| _dS )z2Sets the X coordinate of the right side of the boxN)r   r   minr   r-   r   r   r    r3   v   s    
c                 C   s   | j S )z+The Y coordinate of the top edge of the box)r   r*   r   r   r    top|   s    zRectangle.topc                 C   s   || _ t| j| j | _dS )z0Sets the Y coordinate of the top edge of the boxN)r   r2   r   r-   r   r   r    r5      s    c                 C   s   | j S )z.The Y coordinate of the bottom edge of the box)r   r*   r   r   r    bottom   s    zRectangle.bottomc                 C   s   || _ t| j | j| _dS )z3Sets the Y coordinate of the bottom edge of the boxN)r   r4   r   r-   r   r   r    r6      s    c                 C   s   | j | j d S )z)The X coordinate of the center of the box       @r,   r*   r   r   r    midx   s    zRectangle.midxc                 C   s4   || j | j d  }|  j |7  _ |  j|7  _dS )z5Moves the center of the box to the given X coordinater7   Nr,   )r'   r.   dxr   r   r    r8      s    c                 C   s   | j | j d S )z)The Y coordinate of the center of the boxr7   r0   r*   r   r   r    midy   s    zRectangle.midyc                 C   s4   || j | j d  }|  j |7  _ |  j|7  _dS )z5Moves the center of the box to the given Y coordinater7   Nr0   )r'   r.   dyr   r   r    r:      s    c                 C   s   | j | j | j| j fS )z*The shape of the rectangle (width, height))r   r   r   r   r*   r   r   r    shape   s    zRectangle.shapec                 C   s   |\| _ | _dS )z0Sets the shape of the rectangle (width, height).N)r+   r/   )r'   r<   r   r   r    r<      s    c                 C   s   t |tst |tr"t|gd }t|dkr6td| j|d  | j|d   }}| j|d  | j|d   }}||kr|| d }|}||kr|| d }|}| 	||||S )zcContracts the rectangle by the given margins.

        @return: a new L{Rectangle} object.
        r   z,margins must be a 4-tuple or a single numberr   r   r      r7   )
r#   intr   r"   r&   r   r   r   r   	__class__)r'   marginsZnx1Zny1Znx2Zny2r   r   r    contract   s    zRectangle.contractc                 C   s8   t |tst |tr$| t| S | dd |D S )zaExpands the rectangle by the given margins.

        @return: a new L{Rectangle} object.
        c                 S   s   g | ]}t | qS r   r   )r   marginr   r   r    
<listcomp>   s     z$Rectangle.expand.<locals>.<listcomp>)r#   r>   r   rA   )r'   r@   r   r   r    expand   s    zRectangle.expandc                 C   s0   | j |jkp.| j|j k p.| j|jkp.| j|jk S )a  Returns C{True} if the two rectangles have no intersection.

        Example::

            >>> r1 = Rectangle(10, 10, 30, 30)
            >>> r2 = Rectangle(20, 20, 50, 50)
            >>> r3 = Rectangle(70, 70, 90, 90)
            >>> r1.isdisjoint(r2)
            False
            >>> r2.isdisjoint(r1)
            False
            >>> r1.isdisjoint(r3)
            True
            >>> r3.isdisjoint(r1)
            True
        r   r   r   r   r'   otherr   r   r    
isdisjoint   s    


zRectangle.isdisjointc                 C   s   | j | jko| j| jkS )an  Returns C{True} if the rectangle is empty (i.e. it has zero
        width and height).

        Example::

            >>> r1 = Rectangle(10, 10, 30, 30)
            >>> r2 = Rectangle(70, 70, 90, 90)
            >>> r1.isempty()
            False
            >>> r2.isempty()
            False
            >>> r1.intersection(r2).isempty()
            True
        rE   r*   r   r   r    isempty   s    zRectangle.isemptyc                 C   sN   |  |rtddddS tt| j|jt| j|jt| j|jt| j|jS )a  Returns the intersection of this rectangle with another.

        Example::

            >>> r1 = Rectangle(10, 10, 30, 30)
            >>> r2 = Rectangle(20, 20, 50, 50)
            >>> r3 = Rectangle(70, 70, 90, 90)
            >>> r1.intersection(r2)
            Rectangle(20.0, 20.0, 30.0, 30.0)
            >>> r2 & r1
            Rectangle(20.0, 20.0, 30.0, 30.0)
            >>> r2.intersection(r1) == r1.intersection(r2)
            True
            >>> r1.intersection(r3)
            Rectangle(0.0, 0.0, 0.0, 0.0)
        r   )rH   r   r2   r   r   r4   r   r   rF   r   r   r    intersection   s    
zRectangle.intersectionc                 C   s<   |  j |7  _ |  j|7  _|  j|7  _|  j|7  _dS )aN  Translates the rectangle in-place.

        Example:

            >>> r = Rectangle(10, 20, 50, 70)
            >>> r.translate(30, -10)
            >>> r
            Rectangle(40.0, 10.0, 80.0, 60.0)

        @param dx: the X coordinate of the translation vector
        @param dy: the Y coordinate of the translation vector
        NrE   )r'   r9   r;   r   r   r    	translate  s    zRectangle.translatec                 C   s6   t t| j|jt| j|jt| j|jt| j|jS )aW  Returns the union of this rectangle with another.

        The resulting rectangle is the smallest rectangle that contains both
        rectangles.

        Example::

            >>> r1 = Rectangle(10, 10, 30, 30)
            >>> r2 = Rectangle(20, 20, 50, 50)
            >>> r3 = Rectangle(70, 70, 90, 90)
            >>> r1.union(r2)
            Rectangle(10.0, 10.0, 50.0, 50.0)
            >>> r2 | r1
            Rectangle(10.0, 10.0, 50.0, 50.0)
            >>> r2.union(r1) == r1.union(r2)
            True
            >>> r1.union(r3)
            Rectangle(10.0, 10.0, 90.0, 90.0)
        )r   r4   r   r   r2   r   r   rF   r   r   r    union'  s    zRectangle.unionc                 C   sD   t | j|j| _t | j|j| _t| j|j| _t| j|j| _| S )a  Expands this rectangle to include itself and another completely while
        still being as small as possible.

        Example::

            >>> r1 = Rectangle(10, 10, 30, 30)
            >>> r2 = Rectangle(20, 20, 50, 50)
            >>> r3 = Rectangle(70, 70, 90, 90)
            >>> r1 |= r2
            >>> r1
            Rectangle(10.0, 10.0, 50.0, 50.0)
            >>> r1 |= r3
            >>> r1
            Rectangle(10.0, 10.0, 90.0, 90.0)
        r4   r   r   r2   r   r   rF   r   r   r    __ior__D  s
    zRectangle.__ior__c                 C   s   d| j j| j| j| j| jf S )Nz%s(%s, %s, %s, %s))r?   __name__r   r   r   r   r*   r   r   r    __repr__Z  s    zRectangle.__repr__c                 C   s   | j |j kS r   r$   rF   r   r   r    __eq__c  s    zRectangle.__eq__c                 C   s   | j |j kS r   rQ   rF   r   r   r    __ne__f  s    zRectangle.__ne__c                 C   s   | j | jkp| j| jkS r   rE   r*   r   r   r    __bool__i  s    zRectangle.__bool__c                 C   s
   t | jS r   )hashr$   r*   r   r   r    __hash__l  s    zRectangle.__hash__N)!rO   
__module____qualname____doc__	__slots__r)   propertyr$   setterr+   r/   r1   r3   r5   r6   r8   r:   r<   rA   rD   rH   rI   rJ   __and__rK   rL   __or__rN   rP   rR   rS   rT   rV   r   r   r   r    r      st   



















		r   c                   @   s    e Zd ZdZdd Zdd ZdS )r	   zVClass representing a bounding box (a rectangular area) that
    encloses some objects.c                 C   sD   t | j|j| _t | j|j| _t| j|j| _t| j|j| _| S )a6  Replaces this bounding box with the union of itself and
        another.

        Example::

            >>> box1 = BoundingBox(10, 20, 50, 60)
            >>> box2 = BoundingBox(70, 40, 100, 90)
            >>> box1 |= box2
            >>> print(box1)
            BoundingBox(10.0, 20.0, 100.0, 90.0)
        rM   rF   r   r   r    rN   w  s
    zBoundingBox.__ior__c                 C   s8   |  t| j|jt| j|jt| j|jt| j|jS )aU  Takes the union of this bounding box with another.

        The result is a bounding box which encloses both bounding
        boxes.

        Example::

            >>> box1 = BoundingBox(10, 20, 50, 60)
            >>> box2 = BoundingBox(70, 40, 100, 90)
            >>> box1 | box2
            BoundingBox(10.0, 20.0, 100.0, 90.0)
        )r?   r4   r   r   r2   r   r   rF   r   r   r    r^     s    zBoundingBox.__or__N)rO   rW   rX   rY   rN   r^   r   r   r   r    r	   s  s   r	   c                       s8   e Zd ZdZdd Zdd Zdd Z fdd	Z  ZS )

FakeModulez3Fake module that raises an exception for everythingc                 C   s
   || _ dS )zeConstructor.

        @param message: message to print in exceptions raised from this module
        N)_message)r'   messager   r   r    r)     s    zFakeModule.__init__c                 C   s   t | jd S r   )AttributeErrorr`   r'   _r   r   r    __getattr__  s    zFakeModule.__getattr__c                 C   s   t | jd S r   )	TypeErrorr`   rc   r   r   r    __call__  s    zFakeModule.__call__c                    s&   |dkrt  || n
t| jd S )Nr`   )super__setattr__rb   r`   )r'   keyr.   r?   r   r    ri     s    zFakeModule.__setattr__)	rO   rW   rX   rY   r)   re   rg   ri   __classcell__r   r   rk   r    r_     s
   r_   c                   @   s|   e Zd ZdZdd Zdd Zdd ZeZdd	 Zd
d Z	dd Z
dddZdd Zdd Zdd ZdddZedd ZdS )r
   z+Class representing a point on the 2D plane.c                 C   s   | j | j|j | j|j dS )z.Adds the coordinates of a point to another onexyr?   rn   ro   rF   r   r   r    __add__  s    zPoint.__add__c                 C   s   | j | j|j | j|j dS )z3Subtracts the coordinates of a point to another onerm   rp   rF   r   r   r    __sub__  s    zPoint.__sub__c                 C   s   | j | j| | j| dS )z&Multiplies the coordinates by a scalarrm   rp   r'   Zscalarr   r   r    __mul__  s    zPoint.__mul__c                 C   s   | j | j| | j| dS )z#Divides the coordinates by a scalarrm   rp   rs   r   r   r    __div__  s    zPoint.__div__c                 C   s   t | t| j| jfS )zyReturns the polar coordinate representation of the point.

        @return: the radius and the angle in a tuple.
        )r"   r   ro   rn   r*   r   r   r    as_polar  s    zPoint.as_polarc                 C   s.   | j |j  | j|j  }}|| ||  d S )zReturns the distance of the point from another one.

        Example:

            >>> p1 = Point(5, 7)
            >>> p2 = Point(8, 3)
            >>> p1.distance(p2)
            5.0
              ?rm   )r'   rG   r9   r;   r   r   r    distance  s    
zPoint.distancerw   c                 C   s>   t |}| j| jd|  |j|  | jd|  |j|  dS )a  Linearly interpolates between the coordinates of this point and
        another one.

        @param  other:  the other point
        @param  ratio:  the interpolation ratio between 0 and 1. Zero will
          return this point, 1 will return the other point.
              ?rm   )r   r?   rn   ro   )r'   rG   ratior   r   r    interpolate  s
    zPoint.interpolatec                 C   s   | j d | jd  d S )zPReturns the length of the vector pointing from the origin to this
        point.r   rw   rm   r*   r   r   r    length  s    zPoint.lengthc                 C   s<   |   }|dkr"| j| j| jdS | j| j| | j| dS )z|Normalizes the coordinates of the point s.t. its length will be 1
        after normalization. Returns the normalized point.r   rm   )r|   r?   rn   ro   )r'   r"   r   r   r    
normalized  s    zPoint.normalizedc                 C   s   | j d | jd  S )zXReturns the squared length of the vector pointing from the origin
        to this point.r   rm   r*   r   r   r    	sq_length  s    zPoint.sq_lengthr   c                 C   sJ   |s| S t |j| j |j| j }| | j|t|  | j|t|  S )zZReturns the point that is at a given distance from this point
        towards another one.)r   ro   rn   r?   r   r   )r'   rG   rx   angler   r   r    towards  s     zPoint.towardsc                 C   s   | |t | |t| S )zConstructs a point from polar coordinates.

        C{radius} is the distance of the point from the origin; C{angle} is the
        angle between the X axis and the vector pointing to the point from
        the origin.
        )r   r   )clsradiusr   r   r   r    	FromPolar  s    zPoint.FromPolarN)rw   )r   )rO   rW   rX   rY   rq   rr   rt   __rmul__ru   rv   rx   r{   r|   r}   r~   r   classmethodr   r   r   r   r    r
     s   

r
   Z_Pointrn   ro   c                 C   s   dd | D } dd t | ddD }dd |D }|gt|  }tt|D ]6}|dkr\dn|d	 }||| || g}t|||< qL|S )
a  Given a list of points and a desired corner radius, returns a list
    containing proposed corner radii for each of the points such that it is
    ensured that the corner radius at a point is never larger than half of
    the minimum distance between the point and its neighbors.
    c                 S   s   g | ]}t | qS r   )r
   )r   pointr   r   r    rC      s     z*calculate_corner_radii.<locals>.<listcomp>c                 S   s   g | ]\}}|| qS r   r   )r   uvr   r   r    rC   !  s     T)Zcircularc                 S   s   g | ]}|  d  qS )r   )r|   )r   Zsider   r   r    rC   "  s     r   r   )r   r"   ranger4   )ZpointsZcorner_radiusZ	side_vecsZhalf_side_lengthsZcorner_radiiidxZprev_idxZradiir   r   r    r     s    r   c                 C   s   t ||  || S )zCComputes the Euclidean distance between points (x1,y1) and (x2,y2).)r   )x1y1x2y2r   r   r    r   +  s    r   c	                 C   s   d| d |  d| d| d  |  d|d  d|  |  |d |  }	d| d | d| d| d  |  d|d  d|  |  |d |  }
|	|
fS )zEvaluates the Bezier curve from point (x0,y0) to (x3,y3)
    via control points (x1,y1) and (x2,y2) at t. t is typically in the range
    [0; 1] such that 0 returns (x0, y0) and 1 returns (x3, y3).
    ry   r=         @r   r   )x0y0r   r   r   r   x3y3tZxtZytr   r   r    r   0  s"    

r   c                 C   s   d|  | d |d ||   d| | d |d ||    f}| d|  d |d ||   |d|  d |d ||    f}||fS )zyHelper function that calculates the Bezier control points for a
    curved edge that goes from (x1, y1) to (x2, y2).
    r   r   rw   r   )r   r   r   r   Z	curvatureZaux1Zaux2r   r   r    r   D  s    

r   
   c
              
   C   sN  |d }
t | |||}t|}d}d||  }t| ||||||||	\}}d}t ||||}d}t|| |
kr6||	k r6|| dk|| dkkr|| d }n6t|| t|| k r||| d  }n|||  }|dkrdn|dk rdn|}|| }}|}t| ||||||||	\}}t ||||}|d7 }q`t| ||||||||	S )zBinary search solver for finding the intersection of a Bezier curve
    and a circle centered at the curve's end point.

    Returns the x, y coordinates of the intersection point.
    g      4@ry   r   r7   r   )r   r   r   abs)r   r   r   r   r   r   r   r   r   Zmax_iter	precisionZsource_target_distancet0t1Zxt1Zyt1Zdistance_t0Zdistance_t1counterZt_newr   r   r    r   S  s,    

r   Fc                 C   sv   ddddddddddd
}ddg| }|j |||d ddg| }|j |||d || | }|dkrrtd	| |S )
a  Tries to interpret a string as an orientation value.

    The following basic values are understood: ``left-right``, ``bottom-top``,
    ``right-left``, ``top-bottom``. Possible aliases are:

      - ``horizontal``, ``horiz``, ``h`` and ``lr`` for ``left-right``

      - ``vertical``, ``vert``, ``v`` and ``tb`` for top-bottom.

      - ``lr`` for ``left-right``.

      - ``rl`` for ``right-left``.

    ``reversed_horizontal`` reverses the meaning of ``horizontal``, ``horiz``
    and ``h`` to ``rl`` (instead of ``lr``); similarly, ``reversed_vertical``
    reverses the meaning of ``vertical``, ``vert`` and ``v`` to ``bt``
    (instead of ``tb``).

    Returns one of ``lr``, ``rl``, ``tb`` or ``bt``, or throws ``ValueError``
    if the string cannot be interpreted as an orientation.
    lrrltbbt)
z
left-rightz
right-left
top-bottom
bottom-topztop-downz	bottom-upr   r   tdZbu)
horizontalZhorizh)verticalZvertr   )r   r   r   r   zunknown orientation: %s)updategetr&   )r.   Zreversed_horizontalZreversed_verticalaliasesdirresultr   r   r    r     s&    r   curvedc                 C   s.  t t}| jD ]@}|j\}}||kr:|||f |j q|||f |j q|g|   }| D ]}t|dk rxqft|d dkrd||	 < dt|d  }	|	d }
}t
|D ]X\}}| j| }|j|jkr| |	 ||< n||	 ||< |d dkr|	|
7 }	|d9 }qqf|dkr |S || j|< dS )a  Calculates curvature values for each of the edges in the graph to make
    sure that multiple edges are shown properly on a graph plot.

    This function checks the multiplicity of each edge in the graph and
    assigns curvature values (numbers between -1 and 1, corresponding to
    CCW (-1), straight (0) and CW (1) curved edges) to them. The assigned
    values are either stored in an edge attribute or returned as a list,
    depending on the value of the I{attribute} argument.

    @param graph: the graph on which the calculation will be run
    @param attribute: the name of the edge attribute to save the curvature
      values to. The default value is C{curved}, which is the name of the
      edge attribute the default graph plotter checks to decide whether an
      edge should be curved on the plot or not. If I{attribute} is C{None},
      the result will not be stored.
    @param default: the default curvature for single edges. Zero means that
      single edges will be straight. If you want single edges to be curved
      as well, try passing 0.5 or -0.5 here.
    @return: the list of curvature values if I{attribute} is C{None},
      otherwise C{None}.
    r   r   r   r7   r   N)r   listesr%   appendindexZecountvaluesr"   pop	enumeratesourcetarget)graph	attributedefaultZmultiplicitiesedger   r   r   ZeidsZcurveZdcurvesignr   Zeidr   r   r    r     s2    




r   N)r   )FF)r   r   )rY   collectionsr   mathr   r   r   r   typingr   Zigraph.utilsr   __all__r   r	   r_   r   r
   r   r   r   r   r   r   r   r   r   r   r    <module>   s&     Z."_ 
-
0