Ë
    :vžjäz  ã                   ó¤  — d Z ddlZddlZddlmZmZmZ ddlm	Z	m
Z
 ddlmZ ddlmZmZmZmZmZmZmZ 	 ddlmZmZ dd	lmZ 	 ddlZd+d
„Zdee   fd„Z d„ Z!d„ Z"d„ Z#d„ Z$d,dededz  fd„Z%	 	 	 	 d-de&de&dedz  dede'f
d„Z(	 d.dedefd„Z)d/d„Z*dede'e   fd„Z+dededeez  fd„Z,d0d „Z-d,d!„Z.d1d"„Z/d2d#edz  d$edz  fd%„Z0	 d/ded&edz  de1e&e&f   fd'„Z2d(„ Z3d/d)„Z4d/d*„Z5y# e$ r@Z ej8                  e«      Z ej8                  e«      Z ej8                  e«      ZY dZ[ŒádZ[ww xY w# e$ rZ ej8                  e«      ZY dZ[�ŒdZ[ww xY w)3z×
graph.py
-------------

Deal with graph operations. Primarily deal with graphs in (n, 2)
edge list form, and abstract the backend graph library being used.

Currently uses networkx or scipy.sparse.csgraph backend.
é    Né   )Ú
exceptionsÚgroupingÚutil)ÚlogÚtol)Úfaces_to_edges)Ú	ArrayLikeÚGraphEngineTypeÚIntegerÚNDArrayÚNumberÚSequenceÚint64)Ú
coo_matrixÚcsgraph)ÚcKDTreec                 ó®  — |€#t        | d¬«      \  }}|j                  d¬«       n|j                  }|j                  }t	        j
                  |d¬«      }t        |«      dk(  rt        j                  d	«       ||   }|dd…df   |dd…df   k7  }||   }|j                  d¬«       |r,||dd…df   |      }t        |«      t        |«      k(  sJ ‚||fS |S )
a®  
    Returns an (n, 2) list of face indices.
    Each pair of faces in the list shares an edge, making them adjacent.


    Parameters
    -----------
    faces : (n, 3) int, or None
        Vertex indices representing triangles
    mesh : Trimesh object
        If passed will used cached edges
        instead of generating from faces
    return_edges : bool
        Return the edges shared by adjacent faces

    Returns
    ----------
    adjacency : (m, 2) int
        Indexes of faces that are adjacent
    edges: (m, 2) int
        Only returned if return_edges is True
        Indexes of vertices which make up the
        edges shared by the adjacent faces

    Examples
    ----------
    This is useful for lots of things such as finding
    face- connected components:
    ```python
    >>> graph = nx.Graph()
    >>> graph.add_edges_from(mesh.face_adjacency)
    >>> groups = nx.connected_components(graph_connected)
    ```
    NT)Úreturn_indexr   ©Úaxisé   ©Úrequire_countr   z3No adjacent faces detected! Did you merge vertices?)	r	   ÚsortÚedges_sortedÚ
edges_facer   Ú
group_rowsÚlenr   Údebug)	ÚfacesÚmeshÚreturn_edgesÚedgesr   Úedge_groupsÚ	adjacencyÚnondegenerateÚadjacency_edgess	            ú^/workspace/moltex-experiments/.pixi/envs/default/lib/python3.12/site-packages/trimesh/graph.pyÚface_adjacencyr*   -   sô   € ðH €|ô +¨5¸tÔDÑˆˆzà�
‰
˜ˆ
Õð ×!Ñ!ˆØ—_‘_ˆ
ô ×%Ñ% e¸1Ô=€Kä
ˆ;Ó˜1ÒÜ�	‰	ÐGÔHð
 ˜;Ñ'€Ið ša ˜d‘O y²°A°¡Ñ6€MØ˜-Ñ(€Ið ‡N�N˜€NÔáØ ªA¨q¨DÑ 1°-Ñ @ÑAˆÜ�?Ó#¤s¨9£~Ò5Ð5Ð5Ø˜/Ð)Ð)àÐó    Úreturnc                 ó2  — | j                   }|j                  |z  }|j                  d«       |j                  «        |j	                  «       }t        j                  |j                  dd…df   |j                  dd…df   fdt
        j                  ¬«      }|S )a«  
    Find faces that share a vertex i.e. 'neighbors' faces.
    Relies on the fact that an adjacency matrix at a power p
    contains the number of paths of length p connecting two nodes.
    Here we take the bipartite graph from mesh.faces_sparse to the power 2.
    The non-zeros are the faces connected by one vertex.

    Returns
    ----------
    neighborhood : (n, 2) int
        Pairs of faces which share a vertex
    r   Néÿÿÿÿ)r   Údtype)
Úfaces_sparseÚTÚsetdiagÚeliminate_zerosÚtocooÚnpÚconcatenateÚrowÚcolr   )r"   ÚVTÚTTÚneighborhoods       r)   Úface_neighborhoodr<   {   s|   € ð 
×	Ñ	€BØ	�‰�‰€BØ‡J�Jˆq„MØ×ÑÔØ	�‰‹€BÜ—>‘>Ø	�‰’�4�‰˜"Ÿ&™&¢ D ™/Ð*°¼2¿8¹8ô€Lð Ðr+   c           
      óö  — t        j                  | j                  t         j                  ¬«      dz
  }| j                  }t        | j                  j                  «      D ]˜  \  }}| j                  |   }t        j                  t        j                  ||dd…df   j                  d«      k(  ||dd…df   j                  d«      k(  «      «      }|j                  d¬«      dk(  }d|| dd…f<   ||   |||f<   Œš |S )a‚  
    Return the vertex index of the two vertices not in the shared
    edge between two adjacent faces

    Parameters
    ----------
    mesh : Trimesh object
      Input mesh

    Returns
    -----------
    vid_unshared : (len(mesh.face_adjacency), 2) int
      Indexes of mesh.vertices
      for degenerate faces without exactly
      one unshared vertex per face it will be -1
    ©r/   r   Nr   ©r.   r   r   F)r5   Ú
zeros_liker*   r   Úface_adjacency_edgesÚ	enumerater1   r!   Úlogical_notÚ
logical_orÚreshapeÚsum)r"   Úvid_unsharedr$   ÚiÚfidr!   ÚunsharedÚrow_oks           r)   Úface_adjacency_unsharedrL   ”   sï   € ô( —=‘= ×!4Ñ!4¼B¿H¹HÔEÈÑI€Là×%Ñ%€Eô ˜D×/Ñ/×1Ñ1Ö2‰ˆˆ3à—
‘
˜3‘ˆô —>‘>Ü�M‰MØ˜šq !˜t™×,Ñ,¨WÓ5Ñ5Ø˜šq !˜t™×,Ñ,¨WÓ5Ñ5óó
ˆð —‘ 1�Ó%¨Ñ*ˆà$ˆ�&�š!�Ñà"'¨¡/ˆ�V˜Q�YÒð! 3ð$ Ðr+   c                 ó
  — | j                   t        j                  d«      kD  }t        j                  dt        j                  | j                   |   «      z  «      }| j
                  | j                     }t        j                  |d¬«      j                  d«      }| j                  }t        j                  t        j                  | j
                  |   d¬«      j                  d«      «      }t        j                  |t        j                  ||«      j                  d«      |z  «      }t        j                  |«      }t        j                  t!        | j"                  «      «      t        j$                  z  }	||   |z  |	|<   |	|fS )a¬  
    Compute an approximate radius between adjacent faces.

    Parameters
    --------------
    mesh : trimesh.Trimesh

    Returns
    -------------
    radii : (len(self.face_adjacency),) float
      Approximate radius between faces
      Parallel faces will have a value of np.inf
    span :  (len(self.face_adjacency),) float
      Perpendicular projection distance of two
      unshared vertices onto the shared edge
    g{®Gáz„?g       @r   r   )r.   é   r?   )Úface_adjacency_anglesr5   ÚradiansÚabsÚsinÚverticesrL   ÚdiffrE   rA   r   ÚunitizeÚsubtractÚdiagonal_dotÚrow_normÚonesr   r*   Úinf)
r"   ÚnonzeroÚdenominatorÚpoint_pairsÚvectorsr$   Ú	edges_vecÚperpÚspanÚradiis
             r)   Úface_adjacency_radiusrc   Â   s1  € ð, ×(Ñ(¬2¯:©:°dÓ+;Ñ;€GÜ—&‘&˜œrŸv™v d×&@Ñ&@ÀÑ&IÓJÑJÓK€Kð —-‘- × <Ñ <Ñ=€KÜ�g‰g�k¨Ô*×2Ñ2°7Ó;€Gð ×%Ñ%€Eä—‘œRŸW™W T§]¡]°5Ñ%9ÀÔB×JÑJÈ7ÓSÓT€Iô �;‰;Ø”$×#Ñ# G¨YÓ7×?Ñ?ÀÓHÈ9ÑTó€Dô �=‰=˜Ó€Dô �G‰G”C˜×+Ñ+Ó,Ó-´·±Ñ6€EØ˜'‘] [Ñ0€Eˆ'�Nà�$ˆ;Ðr+   c                 ód   — t        j                  «       }|j                  | j                  «       |S )a/  
    Returns a networkx graph representing the vertices and
    their connections in the mesh.

    Parameters
    ----------
    mesh : Trimesh object

    Returns
    ---------
    graph : networkx.Graph
        Graph representing vertices and edges between
        them where vertices are nodes and edges are edges

    Examples
    ----------
    This is useful for getting nearby vertices for a given vertex,
    potentially for some simple smoothing techniques.
    >>> graph = mesh.vertex_adjacency_graph
    >>> graph.neighbors(0)
    > [1, 3, 4]
    )ÚnxÚGraphÚadd_edges_fromÚedges_unique)r"   Úgs     r)   Úvertex_adjacency_graphrj   ó   s(   € ô. 	�‰‹
€AØ×Ñ�T×&Ñ&Ô'Ø€Hr+   c                 óÒ   — t        j                  t        | «      d¬«      }t        j                  t        |«      d¬«      }t        j                  ||t         j
                  ¬«      }|S )a  
    Given two sets of faces, find the edges which are in both sets.

    Parameters
    ---------
    faces_a : (n, 3) int
      Array of faces
    faces_b : (m, 3) int
      Array of faces

    Returns
    ---------
    shared : (p, 2) int
      Edges shared between faces
    r   r   ©Ú	operation)r5   r   r	   r   Úboolean_rowsÚintersect1d)Úfaces_aÚfaces_bÚe_aÚe_bÚshareds        r)   Úshared_edgesru     sK   € ô  �'‰'”. Ó)°Ô
2€CÜ
�'‰'”. Ó)°Ô
2€CÜ×"Ñ" 3¨´r·~±~ÔF€FØ€Mr+   ÚengineÚfacet_thresholdc                 óš  — |€t         j                  }| j                  }| j                  }t	        j
                  t        |«      t        ¬«      }t	        j                  |«      t         j                  kD  }||   ||   z  dz  |kD  ||<   t        | j                  |   t	        j                  t        | j                  «      «      d|¬«      }|S )an  
    Find the list of parallel adjacent faces.

    Parameters
    -----------
    mesh : trimesh.Trimesh
    engine
      Which graph engine to use
    facet_threshold : float
      Threshold for two facets to be considered coplanar

    Returns
    ---------
    facets : sequence of (n,) int
        Groups of face indexes of
        parallel adjacent faces.
    r>   r   )ÚnodesÚmin_lenrv   )r   rw   rc   Úface_adjacency_spanr5   rY   r   ÚboolrQ   ÚzeroÚconnected_componentsr*   Úaranger!   )r"   rv   rw   rb   ra   Úparallelr[   Ú
componentss           r)   Úfacetsr‚   %  s¶   € ð$ ÐÜ×-Ñ-ˆð ×&Ñ&€Eà×#Ñ#€Dô �w‰w”s˜5“z¬Ô.€Hä�f‰f�T‹lœSŸX™XÑ%€Gà˜w™¨$¨w©-Ñ7¸AÑ=ÀÑO€HˆWÑô &Ø×Ñ˜HÑ%Ü�i‰iœ˜DŸJ™J›Ó(ØØô	€Jð Ðr+   Úonly_watertightÚrepairr&   c                 óÂ   — |€| j                   }|rd}nd}t        |t        j                  t	        | j
                  «      «      ||¬«      } | j                  |f||dœ|¤ŽS )a3  
    Split a mesh into multiple meshes from face
    connectivity.

    If only_watertight is true it will only return
    watertight meshes and will attempt to repair
    single triangle or quad holes.

    Parameters
    ----------
    mesh : trimesh.Trimesh
      The source multibody mesh to split
    only_watertight
      Only return watertight components and discard
      any connected component that isn't fully watertight.
    repair
      If set try to fill small holes in a mesh, before the
      discard step in `only_watertight.
    adjacency : (n, 2) int
      If passed will be used instead of `mesh.face_adjacency`
    engine
      Which graph engine to use for the connected components.

    Returns
    ----------
    meshes : (m,) trimesh.Trimesh
      Results of splitting based on parameters.
    é   r   )r$   ry   rz   rv   )rƒ   r„   )r*   r~   r5   r   r   r!   Úsubmesh)r"   rƒ   r„   r&   rv   Úkwargsrz   r�   s           r)   Úsplitr‰   V  st   € ðH ÐØ×'Ñ'ˆ	áà‰ð ˆä%ØœrŸy™y¬¨T¯Z©Z«Ó9À7ÐSYô€Jð ˆ4�<‰<ØðØ$3¸FñØFLñð r+   rz   c                 ó”  ‡ ‡‡‡— ˆ ˆˆfd„}ˆ ˆˆˆfd„}t        j                  ‰ t         j                  ¬«      Š ‰€t        j                  ‰ «      Št	        ‰«      dk(  rg S t	        ‰ «      dk(  r+‰dk  r$t        j
                  ‰d«      j                  «       S g S t        j                  ‰ d«      st        d«      ‚dg}t	        ‰ «      dkD  r|j                  ‰ j                  «       «       t	        ‰«      dkD  r|j                  ‰j                  «       «       t        j                  |«      dz   Št        j                  ‰t        ¬«      }d	|‰<   |‰    j                  d¬
«      }‰ |   Š t        j                   d|fd|ff«      }	||	v r
 |	|   «       S |	j#                  «       D ]  }
	  |
«       c S  t'        d«      ‚# t$        $ r Y Œ$w xY w)aê  
    Find groups of connected nodes from an edge list.

    Parameters
    -----------
    edges : (n, 2) int
      Edges between nodes
    nodes : (m, ) int or None
      List of nodes that exist
    min_len : int
      Minimum length of a component group to return
    engine :  str or None
      Which graph engine to use (None for automatic):
      (None, 'networkx', 'scipy')


    Returns
    -----------
    components : (n,) sequence of (*,) int
      Nodes which are connected
    c                  ó¼   •— t        j                  ‰«      } ‰dk  r| j                  ‰«       t        j                  | «      D �cg c]  }t	        |«      ‘Œ c}S c c}w )z:
        Find connected components using networkx
        r   )re   Úfrom_edgelistÚadd_nodes_fromr~   Úlist)ÚgraphrH   r$   rz   ry   s     €€€r)   Úcomponents_networkxz1connected_components.<locals>.components_networkx¥  sU   ø€ ô × Ñ  Ó'ˆð �aŠ<Ø× Ñ  Ô'Ü!#×!8Ñ!8¸Ô!?Ó@Ñ!?˜A”�Q•Ð!?Ñ@Ð@ùÒ@s   ÁAc                  ó  •— t        ‰‰¬«      } t        j                  ‰t        ¬«      }d|‰<   t        j                  ‰t        j
                  ¬«      |   }t        j                  | |   ‰¬«      }|D �cg c]  }||   ‘Œ	 c}S c c}w )zF
        Find connected components using scipy.sparse.csgraph
        )Ú
node_countr>   T)rz   )Úconnected_component_labelsr5   Úzerosr|   r   r   r   Úgroup)	ÚlabelsÚ	containedÚindexr�   Úcr$   rz   r’   ry   s	        €€€€r)   Úcomponents_csgraphz0connected_components.<locals>.components_csgraph°  sw   ø€ ô
 ,¨E¸jÔIˆô —H‘H˜Z¬tÔ4ˆ	Øˆ	�%ÑÜ—	‘	˜*¬B¯H©HÔ5°iÑ@ˆÜ—^‘^ F¨9Ñ$5¸wÔGˆ
Ù",Ó-¡*˜Q��a“ *Ñ-Ð-ùÒ-s   Á5Br>   r   r   r?   ©r.   r   úedges must be (n, 2)!Tr   ÚscipyÚnetworkxzno graph engines available!)r5   Ú
asanyarrayr   Úuniquer   rE   Útolistr   Úis_shapeÚ
ValueErrorÚappendÚmaxr”   r|   ÚallÚcollectionsÚOrderedDictÚvaluesÚBaseExceptionÚImportError)r$   rz   ry   rv   r�   rš   ÚcountsÚmaskÚedges_okÚenginesÚfunctionr’   s   ```        @r)   r~   r~   Œ  s¢  û€ ö2	A÷ô$ �M‰M˜%¤r§x¡xÔ0€Eà€}Ü—	‘	˜%Ó ˆô ˆ5ƒz�Q‚Øˆ	Ü	ˆU‹�qŠØ�aŠ<Ü—:‘:˜e WÓ-×4Ñ4Ó6Ð6àˆIä�=‰=˜ Ô(ÜÐ0Ó1Ð1ð ˆS€FÜ
ˆ5ƒz�A‚~Ø�‰�e—i‘i“kÔ"Ü
ˆ5ƒz�A‚~Ø�‰�e—i‘i“kÔ"Ü—‘˜“ !Ñ#€Jô �8‰8�J¤dÔ+€DØ€Dˆ�KØ�E‰{�‰ AˆÓ&€HØ�(‰O€Eô ×%Ñ%Ø
Ð%Ð	&¨Ð5HÐ(IÐJó€Gð
 �ÑØˆw�v‰Ó Ð ð —N‘NÖ$ˆð	Ù“:Òð %ô Ð3Ó
4Ð4øô ò 	Ùð	ús   Æ&F;Æ;	GÇGc                 óv   — t        | |«      }t        j                  |d¬«      \  }}|�t        |«      |k(  sJ ‚|S )a?  
    Label graph nodes from an edge list, using scipy.sparse.csgraph

    Parameters
    -----------
    edges : (n, 2) int
       Edges of a graph
    node_count : int, or None
        The largest node in the graph.

    Returns
    ----------
    labels : (node_count,) int
        Component labels for each node
    F)Údirected)Úedges_to_coor   r~   r   )r$   r’   ÚmatrixÚ_body_countr–   s        r)   r“   r“   õ  sD   € ô  ˜% Ó,€FÜ!×6Ñ6°vÈÔNÑ€K�àÐÜ�6‹{˜jÒ(Ð(Ð(à€Mr+   Ú	traversalc                 ó¾  — t        j                  | dd | dd f«      }|j                  t        j                  |d¬«      «      d   dk  }|j	                  «       r| g}nOt        j                  |dd¬«      }|D �cg c],  }t        j                  |dd…df   |   ||d      dd g«      ‘Œ. }}t        j                  |D �cg c]G  }t        |«      d	kD  xr5 |d   |d   k7  xr( |j                  t        |d   |d   g«      «      d   dk  ‘ŒI c}«      }|j                  «       r@t        j                  |«      d   D ]%  }	t        j                  ||	   ||	   dd g«      ||	<   Œ' t        j                  r`|D ][  }t        j                  t        j                  |dd |dd f«      d¬«      }
|j                  |
«      d   dk  j	                  «       rŒ[J ‚ |S c c}w c c}w )
a  
    Given a traversal as a list of nodes split the traversal
    if a sequential index pair is not in the given edges.
    Useful since the implementation of DFS we're using will
    happily return disconnected values in a flat traversal.

    Parameters
    --------------
    traversal : (m,) int
       Traversal through edges
    edges_tree : cKDTree
      A way to reconstruct original edge indices from
      sorted (n, 2) edge values. This is a slight misuse of a
      kdtree since one could just hash the tuples of the integer
      edges, but that isn't possible with numpy arrays easily
      and this allows a vectorized reconstruction.

    Returns
    ---------------
    split : sequence of (p,) int
      Traversals split into only connected paths.
    Nr.   r   r   r   g»½×Ùß|Û=T)rz   Úonly_nonzeror   )r5   Úcolumn_stackÚqueryr   r¦   r   Úblocksr6   Úarrayr   ÚsortedÚanyr[   r   Ústrict)r¶   Ú
edges_treeÚ	trav_edgeÚexistsr‰   r»   ÚbÚsÚneeds_closerH   Ú
check_edges              r)   Ú_split_traversalrÇ     sö  € ô2 —‘ ¨3¨B °¸1¸2°Ð ?Ó@€Ið ×ÑœbŸg™g i°aÔ8Ó9¸!Ñ<¸uÑD€Fà‡z�z„|Ø�‰ô —‘ °ÀÔFˆáPVó
ÙPVÈ1ŒB�N‰N˜I¢a¨ d™O¨AÑ.°	¸!¸B¹%Ñ0@ÀÀÐ0DÐEÕFÐPVð 	ð 
ô —(‘(ñ
 ó		
ñ �ô �‹F�Q‰Jò CØ�!‘˜˜"™‘òCà× Ñ ¤¨¨1©¨q°©u¨Ó!6Ó7¸Ñ:¸UÑBñCð ñ		
ó€Kð ‡�ÔÜ—‘˜KÓ(¨Ô+ˆAÜ—~‘~ u¨Q¡x°°q±¸"¸1°Ð&>Ó?ˆE�!ŠHð ,ô ‡z‚zÛˆAÜŸ™¤§¡°!°C°R°&¸!¸A¸B¸%°Ó!AÈÔJˆJØ×$Ñ$ ZÓ0°Ñ3°eÑ;×@Ñ@ÕBÐBÐBð ð €Lùò1
ùò	
s   Á:1GÃ AGÚ
traversalsr$   c                 ó$  — t        j                  |d¬«      }t        |«      }t        | «      dk(  r|j	                  «       S g }| D ]  }|j                  t        ||¬«      «       Œ  t        j                  |D �cg c]  }t        j                  |dd |dd f«      ‘Œ! c}«      }t        |«      dkD  rI|j                  d¬«       |j                  t        j                  ||t         j                  ¬«      «       |S |j	                  «       }|S c c}w )aÅ  
    Convert a traversal of a list of edges into a sequence of
    traversals where every pair of consecutive node indexes
    is an edge in a passed edge list

    Parameters
    -------------
    traversals : sequence of (m,) int
       Node indexes of traversals of a graph
    edges : (n, 2) int
       Pairs of connected node indexes

    Returns
    --------------
    splits : sequence of (p,) int
       Node indexes of connected traversals
    r   r   r   )r¶   rÀ   Nr.   rl   )r5   r   r   r   ÚcopyÚextendrÇ   r   Úvstack_emptyr¹   r   rn   Ú	setdiff1d)rÈ   r$   rÀ   Úsplitsry   rH   Úincludeds          r)   Úfill_traversalsrÐ   M  sî   € ô& �G‰G�E Ô"€EÜ˜“€Jô ˆ:ƒ˜!ÒØ�z‰z‹|Ðà€FÛˆà�‰Ô&°À:ÔNÕOð ô
 × Ñ ÉFÓ!SÉFÀq¤"§/¡/°1°S°b°6¸1¸Q¸R¸5°/Õ"BÈFÑ!SÓT€HÜ
ˆ8ƒ}�qÒà�‰˜1ˆÔð 	�‰”h×+Ñ+¨E°8ÄrÇ|Á|ÔTÔUð €Mð —‘“ˆà€Mùò "Ts   Á9$Dc                 ó‚  — t        j                  | t         j                  ¬«      } t        | «      dk(  rg S t	        j
                  | d«      st        d«      ‚t        |«      j                  «       j                  «       }|dk(  rt        j                  }n!|dk(  rt        j                  }nt        d«      ‚| j                  d¬	«       t        | «      }t        j                  | j!                  «       «      }t        j"                  |dk(  «      d   }t        j"                  |dkD  «      d   }g }t        j$                  t        |«      dz   t         j&                  ¬«      }t        j(                  ||f«      D ]G  }	||	   rŒ	 |||	d
d
¬«      j+                  t         j                  «      }
|j-                  |
«       d||
<   ŒI |S )a„  
    Given an edge list generate a sequence of ordered depth
    first search traversals using scipy.csgraph routines.

    Parameters
    ------------
    edges : (n, 2) int
      Undirected edges of a graph
    mode :  str
      Traversal type, 'bfs' or 'dfs'

    Returns
    -----------
    traversals : (m,) sequence of (p,) int
      Ordered DFS or BFS traversals of the graph.
    r>   r   r›   zedges are not (n, 2)!ÚbfsÚdfsz(traversal mode must be either dfs or bfsr   r   F)Úi_startÚreturn_predecessorsr²   T)r5   r¼   r   r   r   r¢   r£   ÚstrÚlowerÚstripr   Úbreadth_first_orderÚdepth_first_orderr   r³   ÚbincountÚravelr[   r”   Úbool_r6   Úastyper¤   )r$   ÚmodeÚfuncr�   rÛ   Ú
nodes_leafry   rÈ   ÚvisitedÚstartÚordereds              r)   rÈ   rÈ   |  s}  € ô" �H‰H�U¤"§(¡(Ô+€EÜ
ˆ5ƒz�Q‚Øˆ	Ü�]‰]˜5 'Ô*ÜÐ0Ó1Ð1ô ˆt‹9�?‰?Ó×"Ñ"Ó$€DØˆu‚}Ü×*Ñ*‰Ø	�ŠÜ×(Ñ(‰äÐCÓDÐDð 
‡J�J�A€JÔä˜Ó€Eô �{‰{˜5Ÿ;™;›=Ó)€Hô —‘˜H¨™MÓ*¨1Ñ-€Jä�J‰J�x !‘|Ó$ QÑ'€Eð €Jä�h‰h”s˜8“} qÑ(´·±Ô9€Gô —‘ ¨UÐ 3Ö4ˆØ�5Š>Øñ Ø˜5°eÀeô
ç
‰&”—‘Ó
ð 	ð
 	×Ñ˜'Ô"Øˆ�Òð 5ð Ðr+   c                 ó‚  — t        j                  | t         j                  ¬«      } t        | «      dk(  s!t	        j
                  | d«      st        d«      ‚|€| j                  «       dz   }t        |«      }|€$t        j                  t        | «      t        ¬«      }t        || j                  f|j                  ||f¬«      S )aò  
    Given an edge list, return a boolean scipy.sparse.coo_matrix
    representing the edges in matrix form.

    Parameters
    ------------
    edges : (n, 2) int
      Edges of a graph
    count : int
      The total number of nodes in the graph
      if None: count = edges.max() + 1
    data : (n,) any
      Assign data to each edge, if None will
      be bool True for each specified edge

    Returns
    ------------
    matrix: (count, count) scipy.sparse.coo_matrix
      Sparse COO
    r>   r   r›   rœ   r   )r/   Úshape)r5   rŸ   r   r   r   r¢   r£   r¥   ÚintrY   r|   r   r1   r/   )r$   ÚcountÚdatas      r)   r³   r³   Ã  s•   € ô* �M‰M˜%¤r§x¡xÔ0€EÜ�‹J˜!ŠOœtŸ}™}¨U°GÔ<ÜÐ0Ó1Ð1ð €}Ø—	‘	“˜a‘ˆÜ�‹J€Eð €|Ü�w‰w”s˜5“z¬Ô.ˆä�t˜UŸW™W�o¨T¯Z©ZÀÀu¸~ÔNÐNr+   c                 ó¢  — t        j                  t        «      }|r)| D �cg c]  }||d      j                  |d   «      ‘Œ c} nB| D �cg c]6  }||d      j                  |d   «      ||d      j                  |d   «      f‘Œ8 c} |€| j	                  «       dz   }t        |«      D �cg c]  }t        ||   «      ‘Œ }}|S c c}w c c}w c c}w )a  
    Find the neighbors for each node in an edgelist graph.

    TODO : re-write this with sparse matrix operations

    Parameters
    ------------
    edges : (n, 2) int
      Connected nodes
    directed : bool
      If True, only connect edges in one direction

    Returns
    ---------
    neighbors : sequence
      Vertex index corresponds to set of other vertex indices
    r   r   )r§   ÚdefaultdictÚsetÚaddr¥   ÚrangerŽ   )r$   Ú	max_indexr²   Ú	neighborsÚedgerH   r¼   s          r)   rð   rð   ê  sâ   € ô$ ×'Ñ'¬Ó,€IÙÙ5:Ó;±U¨Tˆ�4˜‘7Ñ	×	Ñ	  Q¡Õ	(°UÓ;ñ ó	
á�ð �t˜A‘wÑ×#Ñ# D¨¡GÓ,¨i¸¸Q¹Ñ.@×.DÑ.DÀTÈ!ÁWÓ.MÒNØò	
ð
 ÐØ—I‘I“K !‘Oˆ	Ü).¨yÔ)9Ó:Ñ)9 AŒT�)˜A‘,ÕÐ)9€EÐ:à€Lùò 	<ùò	
ùò ;s    !CÁ	;CÂ)CÚangleÚfacet_minareac                 ód  — |€t        j                  d«      }t        | j                  «      dk(  r| j	                  «       S | j
                  |k  }| j                  |   }g }d}|�Í| j                  }| j                  |z  }	 | j                  D �	cg c]  }	||	   j                  «       |kD  sŒ|	‘Œ }}	t        |«      dkD  rst        j                  t        | j                  «      t        ¬«      }
d|
t        j                  |«      <   ||
|   j                  d¬«         }t        j                  |«      }t'        |d|¬«      }t        |«      dkD  r|j)                  |«       t        |«      dk(  r| j	                  «       S t        j                  t        j                  |«      «      }t        |«      t        | j                  «      k7  r\t        j*                  t        j,                  t        | j                  «      «      |«      }|j)                  |j/                  d«      «       | j1                  |dd	¬«      }||j2                  d<   t        |j                  «      t        | j                  «      k7  rt#        j$                  d«       |S c c}	w # t         $ r t#        j$                  dd	¬
«       Y �Œ}w xY w)az  
    Return a non-watertight version of the mesh which
    will render nicely with smooth shading by
    disconnecting faces at sharp angles to each other.

    Parameters
    -----------
    mesh : trimesh.Trimesh
      Source geometry
    angle : float or None
      Angle in radians face pairs with angles
      smaller than this will appear smoothed
    facet_minarea : float or None
      Minimum area fraction to consider
      IE for `facets_minarea=25` only facets larger
      than `mesh.area / 25` will be considered.

    Returns
    ---------
    smooth : trimesh.Trimesh
      Geometry with disconnected face patches
    Né   r   r>   Fr   r   zfailed to calculate facetsT)Úexc_infor   )rz   ry   r?   )rƒ   r¤   Úoriginal_componentszface count in smooth wrong!)r5   rP   r   r*   rÊ   rO   Ú
area_facesÚarear‚   rF   rY   r!   r|   Úhstackr¦   r    rª   r   Úwarningr~   rË   rÍ   r   rE   r‡   Úmetadata)r"   rò   ró   Úangle_okr&   r‚   ry   ÚareasÚmin_areaÚfr­   r�   r    ÚbrokeÚsmooths                  r)   Úsmooth_shader    s=  € ð. €}Ü—
‘
˜2“ˆô ˆ4×ÑÓ 1Ò$Ø�y‰y‹{Ðð ×)Ñ)¨EÑ1€Hà×#Ñ# HÑ-€Ið €FØ€EàÐ Ø—‘ˆØ—9‘9˜}Ñ,ˆð	Eð "&§¢ÓJ¡˜A°°a±·±³ÀÓ0I’a ˆFÐJÜ�6‹{˜QŠô —w‘wœs 4§:¡:›´dÔ;�Ø*/�”R—Y‘Y˜vÓ&Ñ'à% d¨9¡o×&9Ñ&9¸qÐ&9Ó&AÑB�	äŸ	™	 )Ó,�ô & i¸À%ÔH€Jô ˆ6ƒ{�Q‚Ø×Ñ˜&Ô!ä
ˆ:ƒ˜!Òð �y‰y‹{Ðô �Y‰Y”r—y‘y Ó,Ó-€FÜ
ˆ6ƒ{”c˜$Ÿ*™*“oÒ%ô —‘œRŸY™Y¤s¨4¯:©:£Ó7¸Ó@ˆØ×Ñ˜%Ÿ-™-¨Ó0Ô1ð �\‰\˜*°eÀDˆ\ÓI€Fà-7€F‡O�OÐ)Ñ*ä
ˆ6�<‰<ÓœC §
¡
›OÒ+Ü�‰Ð1Ô2Ø€MùòO Køô ò 	EÜ�K‰KÐ4¸t×DÐDð	Eús+   Â J ÂJÂ*JÂ.BJ ÊJ Ê J/Ê.J/r   c                 óP  — |€t        j                  | d¬«      }t        j                  |d¬«      }t	        t        |«      dz  t        | «      k(  «      }| |   j                  d«      dd…dd…f   j                  }t	        t        j                  |Ž j                  «       «      }||fS )ah  
    Parameters
    -----------
    edges : (n, 2) int
      List of vertex indices
    edges_sorted : (n, 2) int
      Pass vertex indices sorted on axis 1 as a speedup

    Returns
    ---------
    watertight : boolean
      Whether every edge is shared by an even
      number of faces
    winding : boolean
      Whether every shared edge is reversed
    Nr   r   r   r   )r.   r†   rN   )
r5   r   r   r   r|   r   rE   r1   Úequalr¦   )r$   r   ÚgroupsÚ
watertightÚopposingÚwindings         r)   Úis_watertightr
  c  s›   € ð( ÐÜ—w‘w˜u¨1Ô-ˆô × Ñ  ¸QÔ?€Fô ”s˜6“{ Q‘¬3¨u«:Ñ5Ó6€Jð �V‰}×$Ñ$ WÓ-ªa°°1°¨fÑ5×7Ñ7€HÜ”2—8‘8˜XÐ&×*Ñ*Ó,Ó-€Gà�wÐÐr+   c                 ó  — ddl }ddl}|j                  «       5 }t        j                  j
                  j                  | |j                  «       |j                  d|j                  dg«      }ddd«       |S # 1 sw Y   S xY w)zÏ
    Turn a networkx graph into an SVG string
    using graphviz `dot`.

    Parameters
    ----------
    graph: networkx graph

    Returns
    ---------
    svg: string, pictoral layout in SVG format
    r   NÚdotz-Tsvg)	Ú
subprocessÚtempfileÚNamedTemporaryFilere   ÚdrawingÚ	nx_agraphÚ	write_dotÚnameÚcheck_output)r�   r  r  Údot_fileÚsvgs        r)   Úgraph_to_svgr  ˆ  sj   € ó Ûà	×	$Ñ	$Ô	&¨(Ü
�
‰
×Ñ×&Ñ& u¨h¯m©mÔ<Ø×%Ñ% u¨h¯m©m¸WÐ&EÓFˆ÷ 
'ð €J÷ 
'ð €Jús   ™AA6Á6B c                 ó  — |€6t        | j                  «       «      t        | j                  «       «      z  dz   }|dfg}g }g }t        |«      D ]±  }|d   d   }| |   }t        |«      dk(  r3|j	                  |«       t        |«      dk(  r |S |j                  «       }ŒQd}	|j                  «       D ]L  }
||
   j                  «       D ]4  }|	r|j	                  |
|f«       d}	Œ|j	                  |dd |
|fgz   «       Œ6 ŒN Œ³ |S )a*  
    For a networkx MultiDiGraph, find all paths from a source node
    to leaf nodes. This function returns edge instance numbers
    in addition to nodes, unlike networkx.all_simple_paths.

    Parameters
    ---------------
    G : networkx.MultiDiGraph
      Graph to evaluate
    source : hashable
      Node to start traversal at
    cutoff : int
      Number of nodes to visit
      If None will visit all nodes

    Returns
    ----------
    traversals : (n,) list of [(node, edge instance index), ] paths
      Traversals of the multigraph
    Nr   r   r.   TF)r   r$   ry   rî   r¤   ÚpopÚkeys)ÚGÚsourceÚcutoffÚcurrentÚqueuerÈ   Ú_Úcurrent_nodeÚchildrã   ÚnodeÚinstances               r)   Úmultigraph_pathsr%  Ÿ  s  € ð* €~Ü�a—g‘g“i“.¤3 q§w¡w£y£>Ñ1°QÑ6ˆð ˜ˆ{ˆm€Gà€Eà€Jä�6Ž]ˆð ˜r‘{ 1‘~ˆà�,‘ˆäˆu‹:˜Š?ð ×Ñ˜gÔ&ä�5‹z˜QŠØð* Ðð% —i‘i“k‰Gð ˆEàŸ
™
ž�Ø % d¡× 0Ñ 0Ö 2�HÙð  Ÿ™¨¨hÐ'7Ô8Ø %™ð Ÿ™ W¨S¨b \°d¸HÐ5EÐ4FÑ%FÕGñ !3ñ %ð+ ðD Ðr+   c                 ó¼   — g }t        j                  |«      D ]A  \  }}| |d      |d      |d      }|€|j                  |«       Œ.|j                  ||   «       ŒC |S )a\  
    Given a MultiDiGraph traversal, collect attributes along it.

    Parameters
    -------------
    G:          networkx.MultiDiGraph
    traversal:  (n) list of (node, instance) tuples
    attrib:     dict key, name to collect. If None, will return all

    Returns
    -------------
    collected: (len(traversal) - 1) list of attributes
    r   r   )r   Úpairwiser¤   )r  r¶   ÚattribÚ	collectedÚuÚvÚattribss          r)   Úmultigraph_collectr-  ã  sk   € ð €IÜ—‘˜iÖ(‰ˆˆ1Ø�A�a‘D‘'˜!˜A™$‘-  !¡Ñ%ˆØˆ>Ø×Ñ˜WÕ%à×Ñ˜W V™_Õ-ð )ð Ðr+   )NNF)NN)TTNN)r   NN)N)rÒ   )NF)Ng      $@)6Ú__doc__r§   Únumpyr5   Ú r   r   r   Ú	constantsr   r   Úgeometryr	   Útypedr
   r   r   r   r   r   r   Úscipy.sparser   r   Úscipy.spatialr   rª   ÚEÚExceptionWrapperrž   re   r*   r<   rL   rc   rj   ru   r‚   r|   rŽ   r‰   r~   r“   rÇ   rÐ   rÈ   r³   rð   r  Útupler
  r  r%  r-  © r+   r)   Ú<module>r:     s  ðñó ã ç (Ñ (ß Ý $÷÷ ñ ð0ß0Ý%ð(ÛóKð\˜w u™~ó ò2+ò\.òbò8ñ,.˜ð .À&È4Á-ó .ðf !ØØ"&Ø"ñ3àð3ð ð3ð ˜4Ñð	3ð
 ð3ð 
ó3ðn HLñf5Øðf5Ø5Dóf5óRð2< ð <¸¸W¹ó <ð~, ð ,°ð ,¸xÈ'Ñ?Qó ,ó^DóN$OóNñDT˜f t™mð TÀ6ÈDÁ=ó Tðp 8<ñ"Øð"Ø$-°Ñ$4ð"à
ˆ4�ˆ:Ñó"òJó.AôHøðI ò 0à)ˆj×)Ñ)¨!Ó,€GØ)ˆj×)Ñ)¨!Ó,€GØ,�×,Ñ,¨QÓ/…Jûð	0ûð ò (ð 
%ˆ×	$Ñ	$ QÓ	'†Bûð(ús/   ¶C% ÁD- Ã%D*Ã*6D%Ä%D*Ä-EÄ2E
Å
E