3
ƽhL                 @   s
  d Z ddlmZ ddlZddlZddlZddljZej	edddd Z
G dd	 d	eZd
d Zdd Zdd Zdd Zd4ddZG dd dZd5ddZd6ddZdd Zd d! Zd7d#d$Zd%d& Zd'd( Zd8d*d+Zejd,d-d.d/d0 Zejd,d1d.d2d3 ZdS )9zO
A module providing some utility functions regarding Bezier path manipulation.
    )	lru_cacheN   )maxsizec             C   sF   || krdS t || | }tjd|d }tj| d | | jtS )Nr      )minnparangeprodZastypeint)nki r   7/tmp/pip-build-7iwl8md4/matplotlib/matplotlib/bezier.py_comb   s
    r   c               @   s   e Zd ZdS )NonIntersectingPathExceptionN)__name__
__module____qualname__r   r   r   r   r      s   r   c                s   ||  ||  }|| ||  }	||  }
}||  }}|
| ||   t  dk r\td||  }}| |
 }} fdd||||gD \}}}}|| ||	  }|| ||	  }||fS )z
    Return the intersection between the line through (*cx1*, *cy1*) at angle
    *t1* and the line through (*cx2*, *cy2*) at angle *t2*.
    g-q=zcGiven lines do not intersect. Please verify that the angles are not equal or differ by 180 degrees.c                s   g | ]}|  qS r   r   ).0r   )ad_bcr   r   
<listcomp>9   s    z$get_intersection.<locals>.<listcomp>)abs
ValueError)Zcx1Zcy1cos_t1sin_t1Zcx2Zcy2cos_t2sin_t2Z	line1_rhsZ	line2_rhsabcdZa_Zb_Zc_Zd_xyr   )r   r   get_intersection    s    
"r$   c             C   sl   |dkr| || |fS ||  }}| | }}|| |  || |  }	}
|| |  || |  }}|	|
||fS )z
    For a line passing through (*cx*, *cy*) and having an angle *t*, return
    locations of the two points located along its perpendicular line at the
    distance of *length*.
    g        r   )cxcyZcos_tZsin_tlengthr   r   r   r   x1y1Zx2y2r   r   r   get_normal_pointsA   s    r+   c             C   s(   | d d d|  | dd  |  }|S )Nr   r   )betatZ	next_betar   r   r   _de_casteljau1Z   s    $r/   c             C   s`   t j| } | g}x&t| |} |j|  t| dkrP qW dd |D }dd t|D }||fS )z
    Split a Bezier segment defined by its control points *beta* into two
    separate segments divided at *t* and return their control points.
    r   c             S   s   g | ]}|d  qS )r   r   )r   r-   r   r   r   r   k   s    z&split_de_casteljau.<locals>.<listcomp>c             S   s   g | ]}|d qS )r   r,   r   )r   r-   r   r   r   r   l   s    )r   asarrayr/   appendlenreversed)r-   r.   Z	beta_listZ	left_betaZ
right_betar   r   r   split_de_casteljau_   s    


r4                 ?{Gz?c             C   s   | |}| |}||}||}||kr8||kr8t dxrtj|d |d  |d |d  |k rj||fS d||  }	| |	}
||
}||A r|	}|
}|}q:|	}|
}|}q:W dS )a  
    Find the intersection of the Bezier curve with a closed path.

    The intersection point *t* is approximated by two parameters *t0*, *t1*
    such that *t0* <= *t* <= *t1*.

    Search starts from *t0* and *t1* and uses a simple bisecting algorithm
    therefore one of the end points must be inside the path while the other
    doesn't. The search stops when the distance of the points parametrized by
    *t0* and *t1* gets smaller than the given *tolerance*.

    Parameters
    ----------
    bezier_point_at_t : callable
        A function returning x, y coordinates of the Bezier at parameter *t*.
        It must have the signature::

            bezier_point_at_t(t: float) -> Tuple[float, float]

    inside_closedpath : callable
        A function returning True if a given point (x, y) is inside the
        closed path. It must have the signature::

            inside_closedpath(point: Tuple[float, float]) -> bool

    t0, t1 : float
        Start parameters for the search.

    tolerance : float
        Maximal allowed distance between the final points.

    Returns
    -------
    t0, t1 : float
        The Bezier path parameters.
    z3Both points are on the same side of the closed pathr   r   g      ?N)r   r   hypot)bezier_point_at_tinside_closedpatht0t1	tolerancestartendZstart_insideZ
end_insideZmiddle_tZmiddleZmiddle_insider   r   r   *find_bezier_t_intersecting_with_closedpathq   s(    &(r@   c               @   s`   e Zd ZdZdd Zdd Zdd Zedd	 Zed
d Z	edd Z
edd Zdd ZdS )BezierSegmentz
    A d-dimensional Bezier segment.

    Parameters
    ----------
    control_points : (N, d) array
        Location of the *N* control points.
    c                sV   t j| _ jj\ _ _t j j _ fddt jD } jj	| j	 _
d S )Nc                s:   g | ]2}t j jd  t j|t j jd  |   qS )r   )math	factorial_N)r   r   )selfr   r   r      s   z*BezierSegment.__init__.<locals>.<listcomp>)r   r0   _cpointsshaperD   _dr   _ordersrangeT_px)rE   control_pointsZcoeffr   )rE   r   __init__   s    
zBezierSegment.__init__c             C   s>   t j|}t jjd| | jddd t jj|| j | j S )a9  
        Evaluate the Bezier curve at point(s) t in [0, 1].

        Parameters
        ----------
        t : float (k,), array_like
            Points at which to evaluate the curve.

        Returns
        -------
        float (k, d), array_like
            Value of the curve for each point in *t*.
        r   Nr,   )r   r0   powerouterrI   rL   )rE   r.   r   r   r   __call__   s    
zBezierSegment.__call__c             C   s   t | |S )z?Evaluate curve at a single point *t*. Returns a Tuple[float*d].)tuple)rE   r.   r   r   r   
point_at_t   s    zBezierSegment.point_at_tc             C   s   | j S )z The control points of the curve.)rF   )rE   r   r   r   rM      s    zBezierSegment.control_pointsc             C   s   | j S )zThe dimension of the curve.)rH   )rE   r   r   r   	dimension   s    zBezierSegment.dimensionc             C   s
   | j d S )z@Degree of the polynomial. One less the number of control points.r   )rD   )rE   r   r   r   degree   s    zBezierSegment.degreec             C   s|   | j }|dkrtjdt | j}tj|d dddf }tj|d dddf }d||  t|| }t||| | S )a  
        The polynomial coefficients of the Bezier curve.

        .. warning:: Follows opposite convention from `numpy.polyval`.

        Returns
        -------
        float, (n+1, d) array_like
            Coefficients after expanding in polynomial basis, where :math:`n`
            is the degree of the bezier curve and :math:`d` its dimension.
            These are the numbers (:math:`C_j`) such that the curve can be
            written :math:`\sum_{j=0}^n C_j t^j`.

        Notes
        -----
        The coefficients are calculated as

        .. math::

            {n \choose j} \sum_{i=0}^j (-1)^{i+j} {j \choose i} P_i

        where :math:`P_i` are the control points of the curve.
        
   zFPolynomial coefficients formula unstable for high order Bezier curves!r   Nr,   )rU   warningswarnRuntimeWarningrM   r   r   r   )rE   r   Pjr   Z	prefactorr   r   r   polynomial_coefficients   s    z%BezierSegment.polynomial_coefficientsc       
      C   s   | j }|dkr"tjg tjg fS | j}tjd|d dddf |dd  }g }g }xFt|jD ]8\}}tj|ddd }|j| |jtj	|| qdW tj
|}tj
|}tj||dk@ |dk@ }	||	 tj||	 fS )a  
        Return the dimension and location of the curve's interior extrema.

        The extrema are the points along the curve where one of its partial
        derivatives is zero.

        Returns
        -------
        dims : int, array_like
            Index :math:`i` of the partial derivative which is zero at each
            interior extrema.
        dzeros : float, array_like
            Of same size as dims. The :math:`t` such that :math:`d/dx_i B(t) =
            0`
        r   Nr   r,   )rU   r   arrayr\   r   	enumeraterK   rootsr1   Z	full_likeconcatenateZisrealreal)
rE   r   ZCjZdCjZdimsr_   r   pirZin_ranger   r   r   axis_aligned_extrema  s    (


z"BezierSegment.axis_aligned_extremaN)r   r   r   __doc__rN   rQ   rS   propertyrM   rT   rU   r\   rd   r   r   r   r   rA      s   	$rA   c       	      C   s>   t | }|j}t|||d\}}t| || d \}}||fS )an  
    Split a Bezier curve into two at the intersection with a closed path.

    Parameters
    ----------
    bezier : array-like(N, 2)
        Control points of the Bezier segment. See `.BezierSegment`.
    inside_closedpath : callable
        A function returning True if a given point (x, y) is inside the
        closed path. See also `.find_bezier_t_intersecting_with_closedpath`.
    tolerance : float
        The tolerance for the intersection. See also
        `.find_bezier_t_intersecting_with_closedpath`.

    Returns
    -------
    left, right
        Lists of control points for the two Bezier segments.
    )r=   g       @)rA   rS   r@   r4   )	Zbezierr:   r=   Zbzr9   r;   r<   _leftZ_rightr   r   r   )split_bezier_intersecting_with_closedpath3  s    rh   Fc             C   s   ddl m} | j }t|\}}||d
d }|}	d}
d}x\|D ]L\}}|}
|t|d 7 }||dd |krtj|	dd |g}P |}	qBW td|jd}t	|||\}}t|dkr|j
g}|j|j
g}nht|dkr|j|jg}|j|j|jg}n<t|dkr6|j|j|jg}|j|j|j|jg}ntd	|dd }|dd }| jdkr|tj| jd| |g}|tj|| j|d g}nd|tj| jd|
 |gtj| jd|
 |g}|tj|| j|d gtj|| j|d g}|r| r|| }}||fS )z`
    Divide a path into two segments at the point where ``inside(x, y)`` becomes
    False.
    r   )Path   Nr   z*The path does not intersect with the patch      zThis should never be reachedrm   rm   r,   )r,   rj   )pathri   Ziter_segmentsnextr2   r   r`   r   Zreshaperh   LINETOMOVETOZCURVE3ZCURVE4AssertionErrorcodesvertices)rn   Zinsider=   Zreorder_inoutri   Z	path_iterZ
ctl_pointscommandZbegin_insideZctl_points_oldZioldr   Zbezier_pathZbpleftrightZ
codes_leftZcodes_rightZ
verts_leftZverts_rightZpath_inZpath_outr   r   r   split_path_inoutV  sP    

rx   c                s   |d  fdd}|S )z
    Return a function that checks whether a point is in a circle with center
    (*cx*, *cy*) and radius *r*.

    The returned function has the signature::

        f(xy: Tuple[float, float]) -> bool
    rj   c                s$   | \}}|  d | d  k S )Nrj   r   )Zxyr"   r#   )r%   r&   r2r   r   _f  s    zinside_circle.<locals>._fr   )r%   r&   rc   rz   r   )r%   r&   ry   r   inside_circle  s    	r{   c             C   sB   ||  ||  }}|| ||  d }|dkr2dS || || fS )Ng      ?r           )r|   r|   r   )Zx0Zy0r(   r)   ZdxZdyr!   r   r   r   get_cos_sin  s
    r}   h㈵>c             C   sN   t j| |}t j||}t|| }||k r0dS t|t j |k rFdS dS dS )a  
    Check if two lines are parallel.

    Parameters
    ----------
    dx1, dy1, dx2, dy2 : float
        The gradients *dy*/*dx* of the two lines.
    tolerance : float
        The angular tolerance in radians up to which the lines are considered
        parallel.

    Returns
    -------
    is_parallel
        - 1 if two lines are parallel in same direction.
        - -1 if two lines are parallel in opposite direction.
        - False otherwise.
    r   FNr,   )r   Zarctan2r   rb   )Zdx1Zdy1Zdx2Zdy2r=   Ztheta1Ztheta2Zdthetar   r   r   check_if_parallel  s    r   c             C   s~  | d \}}| d \}}| d \}}t || || || || }|dkrrtjd t||||\}	}
|	|
 }}n$t||||\}	}
t||||\}}t|||	|
|\}}}}t|||||\}}}}y8t|||	|
||||\}}t|||	|
||||\}}W nJ tk
rH   d||  d||   }}d||  d||   }}Y nX ||f||f||fg}||f||f||fg}||fS )z
    Given the quadratic Bezier control points *bezier2*, returns
    control points of quadratic Bezier lines roughly parallel to given
    one separated by *width*.
    r   r   rj   z8Lines do not intersect. A straight line is used instead.g      ?r,   )r   cbookZ_warn_externalr}   r+   r$   r   )bezier2widthc1xc1ycmxcmyc2xc2yZparallel_testr   r   r   r   c1x_leftc1y_left	c1x_right	c1y_rightZc2x_leftZc2y_leftZ	c2x_rightZ	c2y_rightZcmx_leftZcmy_leftZ	cmx_rightZ	cmy_right	path_left
path_rightr   r   r   get_parallels  s>     

r   c             C   s>   dd| | |   }dd| ||   }| |f||f||fgS )z
    Find control points of the Bezier curve passing through (*c1x*, *c1y*),
    (*mmx*, *mmy*), and (*c2x*, *c2y*), at parametric values 0, 0.5, and 1.
    g      ?rl   r   )r   r   ZmmxZmmyr   r   r   r   r   r   r   find_control_points  s    r         ?c       %      C   s(  | d \}}| d \}}| d \}	}
t ||||\}}t |||	|
\}}t|||||| \}}}}t|	|
|||| \}}}}|| d || d  }}||	 d ||
 d  }}|| d || d  }}t ||||\}}t|||||| \}} }!}"t|||| ||}#t|||!|"||}$|#|$fS )z
    Being similar to get_parallels, returns control points of two quadratic
    Bezier lines having a width roughly parallel to given one separated by
    *width*.
    r   r   rj   g      ?)r}   r+   r   )%r   r   Zw1ZwmZw2r   r   r   r   Zc3xZc3yr   r   r   r   r   r   r   r   Zc3x_leftZc3y_leftZ	c3x_rightZ	c3y_rightZc12xZc12yZc23xZc23yZc123xZc123yZcos_t123Zsin_t123Z
c123x_leftZ
c123y_leftZc123x_rightZc123y_rightr   r   r   r   r   make_wedged_bezier2!  s&    r   z3.3z2Path.cleaned() and remove the final STOP if needed)alternativec             C   sR   ddl m} | j}|dkrJtjt| j|j|jd}|j	|d< || j|S | S dS )z
    If the ``codes`` attribute of `.Path` *p* is None, return a copy of *p*
    with ``codes`` set to (MOVETO, LINETO, LINETO, ..., LINETO); otherwise
    return *p* itself.
    r   )ri   N)Zdtyper   )
rn   ri   rs   r   fullr2   rt   rp   Z	code_typerq   )pri   r    r   r   r   make_path_regularT  s    
r   zPath.make_compound_path()c             C   s   ddl m} |j|  S )z/Concatenate a list of paths into a single path.r   )ri   )rn   ri   Zmake_compound_path)pathsri   r   r   r   concatenate_pathsf  s    r   )r5   r6   r7   )r7   )r7   F)r~   )r6   r   r5   )re   	functoolsr   rB   rW   numpyr   Zmatplotlib.cbookr   Z	vectorizer   r   r   r$   r+   r/   r4   r@   rA   rh   rx   r{   r}   r   r   r   r   Z
deprecatedr   r   r   r   r   r   <module>   s2   
	!
D~
"
=	
J

3