a
    !h                     @   s   d dl Z d dlmZ d dlmZ d dlmZ d dlmZ dd Z	dd	 Z
d
d Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )    N)MultiPolygon)Polygon)unary_union)explain_validityc                 C   s<   | j dksJ t| jjg}| jD ]}|t|j q"|S )z
    Return a list of lists of coordinates of the polygon. The list consists firstly of the list of exterior
    coordinates followed by zero or more lists of any interior coordinates.
    r   )	geom_typelistexteriorcoords	interiorsappend)shaper	   Zinterior r   h/var/www/staging/api/virtual_environments/venv/lib/python3.9/site-packages/mapbox_vector_tile/polygon.py_coords   s
    
r   c                 C   sF   | j dksJ g }| jD ] }tt|jdkr|| qt| j|S )z
    Drop degenerate (zero-size) inners from the polygon.

    This is implemented as dropping anything with a size less than 0.5, as the polygon is in integer coordinates and
    the smallest valid inner would be a triangle with height and width 1.
    r   g      ?)r   r
   absr   Zarear   r   )r   Z
new_innersinnerr   r   r   _drop_degenerate_inners   s    
r   c                 C   sB   t | }|js|d}|js>J d| d|j dt| |S )Nr   zContour z did not make valid polygon z	 because )r   is_validbufferZwktr   )Zcontourpolyr   r   r   _contour_to_poly(   s
    
&r   c           	      c   s   t | }td||D ]t}t|| |}g }| || D ]8}t|}|jdkrX|| q6|jdkr6||j q6t|}|j	sJ |V  qdS )z
    Generator which yields a valid shape for each block_size multiple of input contours. This merges together the
    contours for each block before yielding them.
    r   r   r   N)
lenrangeminr   r   r   extendgeomsr   r   )	contours
block_sizeZ
n_contoursijinnerscpZholesr   r   r   _union_in_blocks0   s    


r#   c                 c   s   | D ]}t |}|V  qdS )zH
    Generator which yields a valid polygon for each contour input.
    N)r   )r   r!   r"   r   r   r   _generate_polysF   s    r$   c              	   C   s.  g }g }| j D ]$}t|\}}|| || q| jr`t|dksJJ | jrZ| jg}ng }n| jrt| j}d}t||krt||}nt|}|D ]D}	z|	|	}
W n t
y   Y qY n0 |
js|
d}
|
jr|
}q|jsJ |jdkr||j n
|| g }nt|dks&J ||fS )z
    Recurses down a Clipper PolyTree, extracting the results as Shapely objects.

    Returns a tuple of (list of polygons, list of children)
    r      r   )ZChilds_polytree_node_to_shapelyr   ZIsHoler   ZContourr   r#   r$   
difference	Exceptionr   r   r   r   r   )nodepolygonschildrenchr"   r!   r   r   r    r   diffr   r   r   r&   O   sB    








r&   c                 C   s2   t | \}}t|dksJ t|}|js.J |S )Nr   )r&   r   r   r   )treer*   r+   unionr   r   r   _polytree_to_shapely   s
    
r0   c                 C   s^   t | }t }z(|t|tjd |tjtj}W n tj	yT   t
g  Y S 0 t|S )a  
    Use the pyclipper library to "union" a polygon on its own. This operation uses the even-odd rule to determine
    which points are in the interior of the polygon, and can reconstruct the orientation of the polygon from that.
    The pyclipper library is robust, and uses integer coordinates, so should not produce any additional degeneracies.

    Before cleaning the polygon, we remove all degenerate inners. This is useful to remove inners which have
    collapsed to points or lines, which can interfere with the cleaning process.
    T)r   	pyclipperZ	PyclipperZAddPathsr   Z
PT_SUBJECTZExecute2ZCT_UNIONZPFT_EVENODDZClipperExceptionr   r0   )r   Zclean_shapeZpcresultr   r   r   make_valid_pyclipper   s    r3   c                 C   s$   | j dksJ t| } | js J | S )a  
    Make a polygon valid. Polygons can be invalid in many ways, such as self-intersection, self-touching and
    degeneracy. This process attempts to make a polygon valid while retaining as much of its extent or area as possible.

    First, we call pyclipper to robustly union the polygon. Using this on its own appears to be good for "cleaning"
    the polygon.

    This might result in polygons which still have degeneracies according to the OCG standard of validity - as
    pyclipper does not consider these to be invalid. Therefore, we follow by using the `buffer(0)` technique to
    attempt to remove any remaining degeneracies.
    r   )r   r3   r   r   r   r   r   make_valid_polygon   s    
r5   c                 C   sJ   g }| j D ]6}|jrq
t|}|jdkr6||j  q
|| q
t|S )Nr   )r   is_emptyr5   r   r   r   r   )r   Znew_ggZvalid_gr   r   r   make_valid_multipolygon   s    

r8   c                 C   s4   | j r
| S | jdkrt| } n| jdkr0t| } | S )z<
    Attempt to make any polygon or multipolygon valid.
    r   r   )r6   r   r8   r5   r4   r   r   r   make_it_valid   s    


r9   )r1   Zshapely.geometry.multipolygonr   Zshapely.geometry.polygonr   Zshapely.opsr   Zshapely.validationr   r   r   r   r#   r$   r&   r0   r3   r5   r8   r9   r   r   r   r   <module>   s   	K