
    Mi3{                        S r SSKrSSKrSSKJrJrJr  SSKJ	r	J
r
  SSKJr  SSKJrJrJrJrJrJrJrJrJrJrJr   SSKJrJr  SS	KJr   SSK!r"S+S
 jr#S\\   4S jr$S r%S r&S r'S r( S,S\S\\   4S jjr)    S-S\*S\*S\\   S\S\4
S jjr+ S.S\S\4S jjr,S/S jr-S\S\\   4S jr.S\S\S\\\4   4S jr/S0S  jr0S,S! jr1S1S" jr2 S2S#\\   S$\\   4S% jjr3 S/S\S&\\   S\\*\*4   4S' jjr4S( r5S/S) jr6S/S* jr7g! \ a@  r\R@                  " \5      r\R@                  " \5      r\R@                  " \5      r SrCNSrCff = f! \ a  r\R@                  " \5      r" SrCGNSrCff = f)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ListNDArrayNumberOptionalSequenceTupleUnionint64)
coo_matrixcsgraph)cKDTreec                    Uc  [        U SS9u  p4UR                  SS9  OUR                  nUR                  n[        R
                  " USS9n[        U5      S:X  a  [        R                  " S	5        XE   nUSS2S4   USS2S4   :g  nXg   nUR                  SS9  U(       a+  X5SS2S4   U      n[        U5      [        U5      :X  d   eXh4$ U$ )
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/var/www/eduai.edurigo.com/storigo/production/storigo_env/lib/python3.13/site-packages/trimesh/graph.pyface_adjacencyr.   1   s    H | +5tD


 !!__
 %%e1=K
;1		GH
 'I adOyA6M(I NNNAqD 1- @A?#s9~555))    returnc                 .   U R                   nUR                  U-  nUR                  S5        UR                  5         UR	                  5       n[
        R                  " UR                  SS2S4   UR                  SS2S4   4S[
        R                  S9nU$ )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JJqM	B>>	4"&&D/*288L r/   c           
         [         R                  " U R                  [         R                  S9S-
  nU R                  n[        U R                  R                  5       H  u  p4U R                  U   n[         R                  " [         R                  " XRSS2S4   R                  S5      :H  XRSS2S4   R                  S5      :H  5      5      nUR                  SS9S:H  nSXg) SS24'   XV   XU4'   M     U$ )aN  
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    ( ==!4!4BHHEIL%%E D//112

3 >>MMq!t,,W55q!t,,W55
 1%*$!"'/QY! 3$ r/   c                 
   U R                   [        R                  " S5      :  n[        R                  " S[        R                  " U R                   U   5      -  5      nU R
                  U R                     n[        R                  " USS9R                  S5      nU R                  n[        R                  " [        R                  " U R
                  U   SS9R                  S5      5      n[        R                  " U[        R                  " XF5      R                  S5      U-  5      n[        R                  " U5      n[        R                  " [!        U R"                  5      5      [        R$                  -  n	X   U-  X'   X4$ )ax  
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      s)   , ((2::d+;;G&&rvvd&@&@&IJJKK -- < <=Kggk*227;G %%ERWWT]]5%9BJJ7STI ;;$##G7??H9TD ==D GGC++,-6E][0EN;r/   c                 f    [         R                  " 5       nUR                  U R                  5        U$ )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                     [         R                  " [        U 5      SS9n[         R                  " [        U5      SS9n[        R                  " X#[         R
                  S9nU$ )z
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     sI      ''.)
2C
''.)
2C""3r~~FFMr/   enginefacet_thresholdc                    Uc  [         R                  nU R                  nU R                  n[        R
                  " [        U5      [        S9n[        R                  " U5      [         R                  :  nX6   XF   -  S-  U:  XV'   [        U R                  U   [        R                  " [        U R                  5      5      SUS9nU$ )a6  
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.
rB   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 wws5z.HffTlSXX%G$-7A=OH &H%iiDJJ(	J r/   only_watertightrepairr*   c                     Uc  U R                   nU(       a  SnOSn[        U[        R                  " [	        U R
                  5      5      XdS9nU R                  " U4XS.UD6$ )a  
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(   r}   r~   rz   )r   r   )r.   r   r9   r   r#   r%   submesh)r&   r   r   r*   rz   kwargsr~   r   s           r-   splitr   \  sm    H ''	 %ryyTZZ97J <<$3FL r/   r~   c                   ^ ^^^ U UU4S jnU UUU4S jn[         R                  " T [         R                  S9m Tc  [         R                  " T 5      m[	        T5      S:X  a  / $ [	        T 5      S:X  a-  TS::  a%  [         R
                  " TS5      R                  5       $ / $ [        R                  " T S5      (       d  [        S5      eS/n[	        T 5      S:  a  UR                  T R                  5       5        [	        T5      S:  a  UR                  TR                  5       5        [         R                  " U5      S-   m[         R                  " T[        S9nS	UT'   UT    R                  SS
9nT U   m [        R                   " SU4SU445      n	X9;   a	  X   " 5       $ U	R#                  5        H  n
 U
" 5       s  $    ['        S5      e! [$         a     M'  f = f)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                     > [         R                  " T5      n TS::  a  U R                  T5        [         R                  " U 5       Vs/ s H  n[	        U5      PM     sn$ s  snf )z*
Find connected components using networkx
r   )ri   from_edgelistadd_nodes_fromr   list)graphrL   r(   r~   r}   s     r-   components_networkx1connected_components.<locals>.components_networkx  sU       ' a<  '!#!8!8!?@!?AQ!?@@@s   Ac                    > [        TTS9n [        R                  " T[        S9nSUT'   [        R                  " T[        R
                  S9U   n[        R                  " X   TS9nU Vs/ s H  oBU   PM	     sn$ s  snf )z6
Find connected components using scipy.sparse.csgraph
)
node_countrB   T)r~   )connected_component_labelsr9   zerosr   r   r   r   group)	labels	containedindexr   cr(   r~   r   r}   s	        r-   components_csgraph0connected_components.<locals>.components_csgraph  ss    
 ,EjI HHZt4		%		*BHH5i@^^F$5wG
",-*Qa*---s   +A<rB   r   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     s   2	A $ MM%rxx0E}		%  5zQ		Uqa<::eW-4466I==((011 SF
5zA~eiik"
5zA~eiik"!#J 88Jd+DDKE{A&H(OE %%
%	&5H(IJG
    NN$	: % 3
44  		s   1G
GGc                 r    [        X5      n[        R                  " USS9u  p4Ub  [        U5      U:X  d   eU$ )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     s@      %,F!66vNK6{j(((Mr/   	traversalc                    [         R                  " U SS U SS 45      nUR                  [         R                  " USS95      S   S:  nUR	                  5       (       a  U /nOP[
        R                  " USSS9nU Vs/ s H-  n[         R                  " USS2S4   U   X&S      SS /5      PM/     nn[         R                  " U Vs/ s HR  n[        U5      S	:  =(       a:    US   US   :g  =(       a(    UR                  [        US   US   /5      5      S   S:  PMT     sn5      nUR                  5       (       aA  [         R                  " U5      S    H$  n	[         R                  " XI   XI   SS /5      XI'   M&     [        R                  (       af  U H`  n[         R                  " [         R                  " USS USS 45      SS9n
UR                  U
5      S   S:  R	                  5       (       a  M`   e   U$ s  snf s  snf )
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   g|=T)r~   only_nonzeror   )r9   column_stackqueryr   r   r   blocksr:   arrayr#   sortedanyr_   r   strict)r   
edges_tree	trav_edgeexistsr   r   bsneeds_closerL   
check_edges              r-   _split_traversalr     s   2 3B12 ?@I bggia89!<uDFzz|| FPV
PV1BNNIadOA.	B%0@0DEFPV 	 
 ((
 		
  FQJ C!"C  1qu!67:UBC 		
K K(+A~~ux"1&>?EH , zzA!CR&!AB%!AJJ$$Z03e;@@BBBB  L1
	
s   <4G9AG>
traversalsr(   c                    [         R                  " USS9n[        U5      n[        U 5      S:X  a  UR	                  5       $ / nU  H  nUR                  [        XBS95        M     [        R                  " U Vs/ s H!  n[         R                  " USS USS 45      PM#     sn5      n[        U5      S:  aC  UR                  SS9  UR                  [        R                  " X[         R                  S95        U$ UR	                  5       nU$ s  snf )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   Nr2   rp   )r9   r   r   r#   copyextendr   r   vstack_emptyr   r   rr   	setdiff1d)r   r(   r   splitsr}   rL   includeds          r-   fill_traversalsr   S  s    & GGE"EJ :!zz|F&NO 
   F!SFq"//1Sb61QR5/"BF!STH
8}q1 	h++Er||TU M M "Ts   7(D
c                    [         R                  " U [         R                  S9n [        U 5      S:X  a  / $ [        R
                  " U S5      (       d  [        S5      e[        U5      R                  5       R                  5       nUS:X  a  [        R                  nO"US:X  a  [        R                  nO[        S5      eU R                  SS	9  [        U 5      n[         R                  " U R!                  5       5      n[         R"                  " US:H  5      S   n[         R"                  " US:  5      S   n/ n[         R$                  " [        U5      S-   [         R&                  S9n[         R(                  " XV45       HH  n	X   (       a  M  U" X9S
S
S9R+                  [         R                  5      n
UR-                  U
5        SX'   MJ     U$ )aP  
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)!bfs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     sx   " HHU"((+E
5zQ	]]5'**011 t9??""$Du}**	((CDD 
JJAJE {{5;;=)H HM*1-JJJx!|$Q'E Jhhs8}q(9G  34> ee

&
 	
 	'" 5 r/   c                    [         R                  " U [         R                  S9n [        U 5      S:X  d'  [        R
                  " U S5      (       d  [        S5      eUc  U R                  5       S-   n[        U5      nUc"  [         R                  " [        U 5      [        S9n[        X R                  4UR                  X4S9$ )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   r   )r3   shape)r9   r   r   r#   r   r   r   r   intr]   r   r   r5   r3   )r(   countdatas      r-   r   r     s    * MM%rxx0EJ!Ot}}UG<<011 }		aJE |wws5z.tWWoTZZ~NNr/   c                    [         R                  " [        5      nU(       a*  U  Vs/ s H  oCUS      R                  US   5      PM       nOBU  Vs/ s H5  nX4S      R                  US   5      X4S      R                  US   5      4PM7       nUc  U R	                  5       S-   n[        U5       Vs/ s H  n[        X5   5      PM     nnU$ s  snf s  snf s  snf )aK  
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edgerL   r   s          r-   r   r     s    $ '',I5:;UT47			Q	(U; 	
 Aw##DG,iQ.@.D.DT!W.MN	

 IIK!O	).y)9:)9AT),)9E:L 	<	
 ;s   #C<C1Canglefacet_minareac                 p   Uc  [         R                  " S5      n[        U R                  5      S:X  a  U R	                  5       $ U R
                  U:  nU R                  U   n/ nSnUb  U R                  nU R                  U-  n U R                   V	s/ s H  oU	   R                  5       U:  d  M  U	PM     nn	[        U5      S:  ao  [         R                  " [        U R                  5      [        S9n
SU
[         R                  " U5      '   XJU   R                  SS9   n[         R                  " U5      n['        USUS9n[        U5      S:  a  UR)                  U5        [        U5      S:X  a  U R	                  5       $ [         R                  " [         R                  " U5      5      n[        U5      [        U R                  5      :w  a^  [         R*                  " [         R,                  " [        U R                  5      5      U5      nUR)                  UR/                  S5      5        U R1                  USS	S9nXR2                  S'   [        UR                  5      [        U R                  5      :w  a  ["        R$                  " S5        U$ s  sn	f ! [          a    ["        R$                  " SS	S
9   GN~f = f)a.  
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   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   rJ   r]   r%   r   hstackr   r   r   r   warningr   r   r   r   rI   r   metadata)r&   r   r   angle_okr*   r   r}   areasmin_areafr   r   r   brokesmooths                  r-   smooth_shader	    s4   2 }

2 41$yy{ ))E1H##H-I FE 99},	E "&JAa0IaFJ6{Q wws4::d;*/RYYv&'%9o&9&9q&9&AB			), &i%HJ 6{Q&!
:! yy{ YYryy,-F
6{c$**o% RYYs4::7@%--01 \\*eD\IF-7OO)*
6<<C

O+12MO K  	EKK4tD	Es+   J J0J6B J J J54J5r    c                 H   Uc  [         R                  " U SS9n[        R                  " USS9n[	        [        U5      S-  [        U 5      :H  5      nX   R                  S5      SS2SS24   R                  n[	        [         R                  " U6 R                  5       5      nX54$ )a0  
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    ( wwu1-   Q?F s6{Q3u:56J }$$W-a1f577H288X&**,-Gr/   c                    SSK nSSKnUR                  5        n[        R                  R
                  R                  XR                  5        UR                  SUR                  S/5      nSSS5        U$ ! , (       d  f       W$ = f)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    sk     		$	$	&(


&&umm<%%uhmmW&EF 
' J 
'	& Js   AA55
Bc                    Uc6  [        U R                  5       5      [        U R                  5       5      -  S-   nUS4/n/ n/ n[        U5       H  nUS   S   nX   n[        U5      S:X  a5  UR	                  U5        [        U5      S:X  a    U$ UR                  5       nMS  Sn	UR                  5        HR  n
X   R                  5        H9  nU	(       a  UR	                  X45        Sn	M   UR	                  USS X4/-   5        M;     MT     M     U$ )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+    s   * ~aggi.3qwwy>1Q6 {mGEJ6] r{1~u:? g&5zQ* % iikG E

 % 0 0 2H  '78 % WSb\d5E4F%FG !3 %+ D r/   c                     / n[         R                  " U5       HA  u  pEXS      US      US      nUc  UR                  U5        M.  UR                  Xb   5        MC     U$ )a4  
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_collectr3    se     Ii(aD'!A$-!%>W%W_- ) r/   )NNF)NN)TTNN)r   NN)N)r   )NF)Ng      $@)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+  r3   r/   r-   <module>r?     s%     ( (  $   00%(K\wu~ 2+\.b8. OS0!0;CF;K0j !%)"33 3 	"	3
 3 
3n HLf5f55Df5R2< <W <~, , ,uXwEV?W ,^DN$ONF MQV&!V9A&9IVt ;?""$,Y$7"
4:"J.AHQ  0))!,G))!,G,,Q/J	0  ( 
	$	$Q	'B(s/   D E E6EEE1E,,E1