U
    Ñtœd¨^  ã                   @   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}q´t |d ƒdkrPt|d ƒdd… }q´t |d ƒdkr´dd|d d |d d f}n6t |ƒdkr”t|ƒ}n t |ƒdkr´dd|d |d f}|dkrÄt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 )z©The 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 )zÁReturns 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 )zãConstructs 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 )zÊEvaluates 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rädn|dk rðdn|}|| }}|}t| ||||||||ƒ	\}}t ||||ƒ}|d7 }q`t| ||||||||ƒ	S )z¹Binary 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r”d|| 	¡ < dt|ƒd  }	|	d }
}t
|ƒD ]X\}}| j| }|j|jkrä| |	 ||< n||	 ||< |d dk�r|	|
7 }	|d9 }q¶qf|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