
    Ti3{                        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mZmZmZmZ 	 ddlmZmZ dd	lmZ nB# e$ r:Z ej         e          Z ej         e          Z ej         e          ZY dZ[ndZ[ww xY w	 ddl!Z"n"# e$ rZ ej         e          Z"Y dZ[ndZ[ww xY wd/dZ#dee         fdZ$d Z%d Z&d Z'd Z(	 d0dedee         fdZ)	 	 	 	 d1de*de*dee         dedef
dZ+	 d2dedefdZ,d3dZ-dedee         fdZ.ded edeeef         fd!Z/d4d#Z0d0d$Z1d5d%Z2	 d6d'ee         d(ee         fd)Z3	 d3d ed*ee         dee*e*f         fd+Z4d, Z5d3d-Z6d3d.Z7dS )7z
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ListNDArrayNumberOptionalSequenceTupleUnionint64)
coo_matrixcsgraph)cKDTreeFc                    |+t          | d          \  }}|                    d           n|j        }|j        }t	          j        |d          }t          |          dk    rt          j        d	           ||         }|dddf         |dddf         k    }||         }|                    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	            G/DATA/AppData/hermes/venv/lib/python3.11/site-packages/trimesh/graph.pyface_adjacencyr.   1   s*   H | +5tDDDz


 !_
 %e1===K
;1	GHHH
 ;'I aaadOyA6M-(I NNN *AAAqD 1- @A?##s9~~5555/))    returnc                 $   | j         }|j        |z  }|                    d           |                                 |                                }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JJqMMM	B>	4"&D/*28  L r/   c           
         t          j        | j        t           j                  dz
  }| j        }t          | j        j                  D ]\  }}| j        |         }t          j        t          j	        ||dddf         
                    d          k    ||dddf         
                    d          k                        }|                    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
    r3   r   Nr   r2   r   r   F)r9   
zeros_liker.   r   face_adjacency_edges	enumerater5   r%   logical_not
logical_orreshapesum)r&   vid_unsharedr(   ifidr%   unsharedrow_oks           r-   face_adjacency_unsharedrP      s   ( =!4BHEEEIL%E D/122 2 23
3 >Mqqq!t,,W555qqq!t,,W555 
 
 1%%*$&!!!"'/VQYr/   c                    | j         t          j        d          k    }t          j        dt          j        | j         |                   z            }| j        | j                 }t          j        |d                              d          }| j	        }t          j        t          j        | j        |         d                              d                    }t          j        |t          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{Gz?g       @r   r   )r2      rC   )face_adjacency_anglesr9   radiansabssinverticesrP   diffrI   rE   r   unitizesubtractdiagonal_dotrow_normonesr#   r.   inf)
r&   nonzerodenominatorpoint_pairsvectorsr(   	edges_vecperpspanradiis
             r-   face_adjacency_radiusrg      s9   , (2:d+;+;;G&rvd&@&IJJJKKK - <=Kgk***227;;G %ERWT]5%9BBBJJ7SSTTI ;$#GY77??HH9T D =D GC+,,--6E'][0E'N$;r/   c                 `    t          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_graphrn      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)r9   r   r	   r   boolean_rowsintersect1d)faces_afaces_be_ae_bshareds        r-   shared_edgesry     sZ      '.))
2
2
2C
'.))
2
2
2C"3r~FFFFMr/   enginefacet_thresholdc                    |t           j        }| j        }| j        }t	          j        t          |          t                    }t	          j        |          t           j	        k    }||         ||         z  dz  |k    ||<   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.
    NrB   r   )nodesmin_lenrz   )r   r{   rg   face_adjacency_spanr9   r]   r#   boolrU   zeroconnected_componentsr.   aranger%   )r&   rz   r{   rf   re   parallelr_   
componentss           r-   facetsr   )  s    ( - &E#D ws5zz...HfTllSX%Gw$w-7A=OHW &H%iDJ((	  J r/   T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.
    N   r   )r(   r}   r~   rz   )r   r   )r.   r   r9   r   r#   r%   submesh)r&   r   r   r*   rz   kwargsr~   r   s           r-   splitr   \  s    H '	  %ryTZ997SY  J 4<$3F FL  r/   r~   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                                          S g S t          j         d          st          d	          dg}t	                     dk    r'|
                                                                t	                    dk    r'|
                                                               t          j        |          dz   t          j        t                    }d
|<   |                              d          } |          t          j        d|fd|ff          }	||	v r |	|                     S |	                                D ]}
	  |
            c S # t$          $ r Y w xY wt'          d          )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|                                d t          j        |           D             S )z:
        Find connected components using networkx
        r   c                 ,    g | ]}t          |          S  list.0rL   s     r-   
<listcomp>zEconnected_components.<locals>.components_networkx.<locals>.<listcomp>  s    @@@AQ@@@r/   )ri   from_edgelistadd_nodes_fromr   )graphr(   r~   r}   s    r-   components_networkxz1connected_components.<locals>.components_networkx  sS      '' a<<  '''@@!8!?!?@@@@r/   c                     t                    } t          j        t                    }d|<   t          j        t          j                  |         t          j        | |                   }fd|D             S )zF
        Find connected components using scipy.sparse.csgraph
        )
node_countrB   T)r~   c                      g | ]
}|         S r   r   )r   cindexs     r-   r   zDconnected_components.<locals>.components_csgraph.<locals>.<listcomp>  s    ---Qa---r/   )connected_component_labelsr9   zerosr   r   r   r   group)labels	containedr   r   r(   r~   r   r}   s      @r-   components_csgraphz0connected_components.<locals>.components_csgraph  s    
 ,EjIII HZt444		%	*BH555i@^F9$5wGGG
----*----r/   rB   Nr   r   rC   r2   r   edges must be (n, 2)!Tr   scipynetworkxzno graph engines available!)r9   
asanyarrayr   uniquer#   rI   tolistr   is_shape
ValueErrorappendmaxr   r   allcollectionsOrderedDictvaluesBaseExceptionImportError)r(   r~   r}   rz   r   r   countsmaskedges_okenginesfunctionr   s   ```        @r-   r   r     sL   2	A 	A 	A 	A 	A 	A 	A       $ M%rx000E}	%   5zzQ		Uqa<<:eW--44666I=(( 20111 SF
5zzA~~eiikk"""
5zzA~~eiikk"""!#J 8Jd+++DDKE{A&&H(OE %
%	&5H(IJ G
 wv    NN$$  	8:: 	 	 	H	
3
4
44s   	G((
G54G5c                     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     sO      %,,F!6vNNNK6{{j((((Mr/   	traversalc           	      .  	 t          j        | dd         | dd         f          	                    t          j        	d                    d         dk     }|                                r| g}n%t          j        |dd          }	fd	|D             }t          j        fd
|D                       }|                                rJt          j	        |          d         D ]/}t          j
        ||         ||         dd         g          ||<   0t          j        rr|D ]o}t          j        t          j        |dd         |dd         f          d          }                    |          d         dk                                     sJ p|S )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.
    Nr2   r   r   r   绽|=T)r~   only_nonzeroc                     g | ]<}t          j        d d df         |         |d                  dd          g          =S )Nr   r2   r   )r9   r:   )r   b	trav_edges     r-   r   z$_split_traversal.<locals>.<listcomp>8  sX     
 
 
KLBNIaaadOA.	!B%0@0DEFF
 
 
r/   c           	          g | ]a}t          |          d k    oK|d         |d         k    o9                    t          |d         |d         g                    d         dk     bS )r   r   r2   r   )r#   querysorted)r   s
edges_trees     r-   r   z$_split_traversal.<locals>.<listcomp>?  s     	
 	
 	
  FFQJ C!"C  1qu!6!677:UB	
 	
 	
r/   )r9   column_stackr   r   r   r   blocksarrayanyr_   r:   r   strict)
r   r   existsr   r   needs_closerL   r   
check_edger   s
    `       @r-   _split_traversalr     s   2 3B3122 ?@@I bgia88899!<uDFzz|| 
 FFF
 
 
 
PV
 
 
 (	
 	
 	
 	
 		
 	
 	
 K  @K((+ 	@ 	@A~uQxq"1"&>??E!HH
z C 	C 	CA!CRC&!ABB%!A!AJJJJ$$Z003e;@@BBBBBBLr/   
traversalsr(   c                    t          j        |d          }t          |          }t          |           dk    r|                                S g }| D ]&}|                    t          ||                     't          j        d |D                       }t          |          dk    rK|                    d           |                    t          j
        ||t           j                             n|                                }|S )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   c                 Z    g | ](}t          j        |d d         |dd          f          )S )Nr2   r   )r9   r   r   s     r-   r   z#fill_traversals.<locals>.<listcomp>s  s6    !S!S!Sq"/1SbS61QRR5/"B"B!S!S!Sr/   rp   )r9   r   r   r#   copyextendr   r   vstack_emptyr   rr   	setdiff1d)r   r(   r   splitsr}   includeds         r-   fill_traversalsr   S  s   & GE"""EJ :!zz||F P P&:NNNOOOO  !S!SF!S!S!STTH
8}}q1 	h+E8r|TTTUUUU Mr/   bfsc                    t          j        | t           j                  } t          |           dk    rg S t	          j        | d          st          d          t          |                                          	                                }|dk    rt          j        }n"|dk    rt          j        }nt          d          |                     d	           t          |           }t          j        |                                           }t          j        |dk              d         }t          j        |dk              d         }g }t          j        t          |          dz   t           j                  }t          j        ||f          D ]Q}	||	         r |||	d
d
                              t           j                  }
|                    |
           d||
<   R|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.
    rB   r   r   zedges are not (n, 2)!r   dfsz(traversal mode must be either dfs or bfsr   r   F)i_startreturn_predecessorsr   T)r9   r   r   r#   r   r   r   strlowerstripr   breadth_first_orderdepth_first_orderr   r   bincountravelr_   r   bool_r:   astyper   )r(   modefuncr   r   
nodes_leafr}   r   visitedstartordereds              r-   r   r     s   " HU"(+++E
5zzQ	]5'** 20111 t99??""$$Du}}*	(CDDD 
JJAJE {5;;==))H HM**1-JJx!|$$Q'E Jhs8}}q(999G U 344    5> 	 $5ee
 
 

&

 	
 	'"""r/   c                    t          j        | t           j                  } t          |           dk    s$t	          j        | d          st          d          ||                                 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
    rB   r   r   r   Nr   )r3   shape)r9   r   r   r#   r   r   r   r   intr]   r   r   r5   r3   )r(   countdatas      r-   r   r     s    * M%rx000EJJ!OOt}UG<<O0111 }		aJJE |ws5zz...tUWoTZu~NNNNr/   c                     t          j        t                    |rfd| D              nfd| D              ||                                 dz   }fdt	          |          D             }|S )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
    c                 ^    g | ])}|d                                        |d                   *S r   r   addr   edge	neighborss     r-   r   zneighbors.<locals>.<listcomp>  s4    ;;;T47			Q	(	(;;;r/   c                     g | ]P}|d                                        |d                   |d                                       |d                    fQS r   r   r   s     r-   r   zneighbors.<locals>.<listcomp>  sd     	
 	
 	
 tAw##DG,,iQ.@.D.DT!W.M.MN	
 	
 	
r/   Nr   c                 :    g | ]}t          |                   S r   r   )r   rL   r   s     r-   r   zneighbors.<locals>.<listcomp>  s%    :::AT)A,:::r/   )r   defaultdictsetr   range)r(   	max_indexr   r   r   s       @r-   r   r     s    $ ',,I 
;;;;U;;;;;	
 	
 	
 	
	
 	
 	
 	

 IIKK!O	::::y)9)9:::ELr/         $@anglefacet_minareac                 X   |t          j        d          }t          | j                  dk    r|                                 S | j        |k     }| j        |         }g }d}|| j        | j        |z  	 fd| j        D             }t          |          dk    rzt          j	        t          | j
                  t                    }d|t          j        |          <   |||                             d                   }t          j        |          }n&# t          $ r t!          j        d	d
           Y nw xY wt%          |d|          }t          |          dk    r|                    |           t          |          dk    r|                                 S t          j        t          j        |                    }	t          |	          t          | j
                  k    rat          j        t          j        t          | j
                            |	          }
|                    |
                    d                     |                     |dd
          }||j        d<   t          |j
                  t          | j
                  k    rt!          j        d           |S )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   c                 P    g | ]"}|                                          k     |#S r   )rJ   )r   fareasmin_areas     r-   r   z smooth_shade.<locals>.<listcomp>A  s/    JJJAa0I0Ia0I0I0Ir/   rB   Fr   r   zfailed to calculate facetsT)exc_infor   )r~   r}   rC   )r   r   original_componentszface count in smooth wrong!)r9   rT   r#   r.   r   rS   
area_facesarear   r]   r%   r   hstackr   r   r   r   warningr   r   r   r   rI   r   metadata)r&   r  r	  angle_okr*   r   r}   r   r   r   brokesmoothr  r  s               @@r-   smooth_shader    s   2 }
2 41$$yy{{ )E1H#H-I FE 9},	E KJJJJJJJF6{{Q ws4:d;;;*/RYv&&'%d9o&9&9q&9&A&AB		),, 	E 	E 	EK4tDDDDDD	E &i%HHHJ 6{{Q&!!!
:! yy{{ Yry,,--F
6{{c$*oo%% RYs4:77@@%--00111 \\*eD\IIF-7FO)*
6<C
OO++1222Ms   5B!D  D:9D:r    c                 x   |t          j        | d          }t          j        |d          }t	          t          |          dz  t          |           k              }| |                             d          ddddf         j        }t	          t          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   )r2   r   rR   )
r9   r   r   r"   r   r#   rI   r5   equalr   )r(   r    groups
watertightopposingwindings         r-   is_watertightr!  k  s    ( wu1---  Q???F s6{{Q3u::566J V}$$W--aaa1f57H28X&**,,--Gwr/   c                     ddl }ddl}|                                5 }t          j        j                            | |j                   |                    d|j        dg          }ddd           n# 1 swxY w Y   |S )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NamedTemporaryFileri   drawing	nx_agraph	write_dotnamecheck_output)r   r$  r%  dot_filesvgs        r-   graph_to_svgr.    s     OOO		$	$	&	& G(

&&uhm<<<%%uhmW&EFFG G G G G G G G G G G G G G G Js   AA11A58A5c                    |Ft          |                                           t          |                                           z  dz   }|dfg}g }g }t          |          D ]}|d         d         }| |         }t          |          dk    r?|                    |           t          |          dk    r n|                                }jd}	|                                D ]^}
||
                                         D ]A}|	r|                    |
|f           d}	|                    |dd         |
|fgz              B_|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   r2   TF)r#   r(   r}   r  r   popkeys)Gsourcecutoffcurrentqueuer   _current_nodechildr   nodeinstances               r-   multigraph_pathsr<    sn   * ~aggii..3qwwyy>>1Q6 {mGEJ6]] !H !H r{1~,u::?? g&&&5zzQ iikkGG E

 H H %d 0 0 2 2 H HH 
H  h'7888 % WSbS\dH5E4F%FGGGGHH r/   c                     g }t          j        |          D ]^\  }}| |d                  |d                  |d                  }||                    |           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   )r2  r   attrib	collecteduvattribss          r-   multigraph_collectrD    s     Ii(( . .1AaD'!A$-!%>W%%%%WV_----r/   )NNF)NN)TTNN)r   NN)N)r   )NF)Nr  )8__doc__r   numpyr9    r   r   r   	constantsr   r   geometryr	   typedr
   r   r   r   r   r   r   r   r   r   r   scipy.sparser   r   scipy.spatialr   r   EExceptionWrapperr   ri   r.   r@   rP   rg   rn   ry   r   r   r   r   r   r   r   r   r   r   r  r!  r.  r<  rD  r   r/   r-   <module>rO     s            ( ( ( ( ( ( ( ( ( (         $ $ $ $ $ $                         000000000%%%%%%% 0 0 0)j)!,,G)j)!,,G,,Q//JJJJJJ	0( ( ( ( 
%	$Q	'	'BBBBBB(K K K K\wu~    2+ + +\. . .b  8  . OS0 0!0;CF;K0 0 0 0j !%)"3 33 3 	"	3
 3 
3 3 3 3n HLf5 f5f55Df5 f5 f5 f5R   2< <W < < < <~, , ,uXwEV?W , , , ,^D D D DN$O $O $O $ON   F MQV V&!V9A&9IV V V Vt ;?" ""$,Y$7"
4:" " " "J  .A A A AH     s/   A B0BBB B4B//B4