
    TiJm                         d dl Z d dlmZ d dlZddlmZmZ ddlmZ ddl	m
Z
mZmZ ddlmZmZmZmZmZmZmZ  ej        d          Zd	ej        d
<    G d d          Z G d d          Z	 ddZdS )    N)deepcopy   )cachingutil)	hash_fast)	fix_rigidquaternion_matrixrotation_matrix)	ArrayLikeHashableNDArrayOptionalSequenceTupleUnion   F	WRITEABLEc            
          e Zd ZdZd dZd!dZ	 d!dedee         d	ee	e
j                 ee         f         fd
Zd Zd Zd Zd!dZd Zd"dZd Zd Zd Zej        d             Zej        d             Zej        d             Zdeeeef         fdZded	e fdZ!ded	ee	e
j                 ee         f         fdZ"dede#fdZ$d Z%dS )#
SceneGraphz
    Hold data about positions and instances of geometry
    in a scene. This includes a forest (i.e. multi-root tree)
    of transforms and information on which node is the base
    frame, and which geometries are affiliated with which
    nodes.
    worldh㈵>c                     t                      | _        || _        || _        t	          j        | j                  | _        dS )a7  
        Create a scene graph, holding homogeneous transformation
        matrices and instance information about geometry.

        Parameters
        -----------
        base_frame : any
          The root node transforms will be positioned from.
        repair_rigid : None or float
          If a float will attempt to repair rotation matrices
          where `M @ M.T` differs from an identity matrix by
          more than floating point zero but less than this value.
          This can happen in a deep tree with a lot of matrix
          multiplies.
        N)EnforcedForest
transforms
base_framerepair_rigidr   Cache__hash___cache)selfr   r   s      R/DATA/AppData/hermes/venv/lib/python3.11/site-packages/trimesh/scene/transforms.py__init__zSceneGraph.__init__   s9    " )**$ )mDM22    Nc                     || j         }d |                                D             }t          di ||d<    | j        j        ||fi | d|v r|d         | j        j        |         d<   dS dS )aB  
        Update a transform in the tree.

        Parameters
        ------------
        frame_from : hashable object
          Usually a string (eg 'world').
          If left as None it will be set to self.base_frame
        frame_to :  hashable object
          Usually a string (eg 'mesh_0')
        matrix : (4,4) float
          Homogeneous transformation matrix
        quaternion :  (4,) float
          Quaternion ordered [w, x, y, z]
        axis : (3,) float
          Axis of rotation
        angle :  float
          Angle of rotation, in radians
        translation : (3,) float
          Distance to translate
        geometry : hashable
          Geometry object name, e.g. 'mesh_0'
        metadata: dictionary
          Optional metadata attached to the new frame
          (exports to glTF node 'extras').
        Nc                 "    i | ]\  }}|d v 	||S )>   geometrymetadata .0kvs      r!   
<dictcomp>z%SceneGraph.update.<locals>.<dictcomp>S   s)    QQQA18P3P3P13P3P3Pr#   matrixr&   r(   )r   itemskwargs_to_matrixr   add_edge	node_data)r    frame_to
frame_fromkwargsattrs        r!   updatezSceneGraph.update3   s    8 J RQQQQ)33F33X 	! X>>>>> >DZ>PDO%h/
;;;  r#   r3   r4   returnc                    || j         }||f}|| j        v r| j        |         S | j        j        |                             d          }| j        j        }||k    r	t          }nI||v r||         d         }n5| j                            ||          }|d         |k    sJ |d         |k    sJ g }t          |dd         |dd                   D ]\  }	}
|                    |	|
f          }| d|v r|	                    |d                    >||
|	f         }d|v r8|	                    t          j                            |d                              d |D             }t          |          dk    rt          }n0t          |          dk    r	|d         }nt          j        |          }| j        t#          || j                  }d	|j        d
<   ||f| j        |<   ||fS )aP  
        Get the transform from one frame to another.

        Parameters
        ------------
        frame_to : hashable
          Node name, usually a string (eg 'mesh_0')
        frame_from : hashable
          Node name, usually a string (eg 'world').
          If None it will be set to self.base_frame

        Returns
        ----------
        transform : (4, 4) float
          Homogeneous transformation matrix
        geometry
          The name of the geometry if it exists

        Raises
        -----------
        ValueError
          If the frames aren't connected.
        Nr&   r.   r      c                 v    g | ]6}t          j        |t          z
                                            d k    4|7S ):0yE>)npabs	_identitymax)r*   ms     r!   
<listcomp>z"SceneGraph.get.<locals>.<listcomp>   s<    RRRarva)m/D/D/H/H/J/JT/Q/Q/Q/Q/Qr#   )max_devianceFr   )r   r   r   r2   get	edge_datar@   shortest_pathzipappendr>   linalginvlenr   	multi_dotr   r   flags)r    r3   r4   keyr&   datar.   pathmatricesur,   forwardbackwards                r!   rE   zSceneGraph.get_   s*   8 J 8$$+;s## ?,X6:::FF (!!FFD[[#Yx(FF
 ?00XFFD7j((((8x'''' HD"ItABBx00 G G1((Aq6**&7** (9:::  A<x''OOBIMM(82D$E$EFFFRR8RRRH8}}!!"X!##!! 11 (vD4EFFFF %*[! #H-Cxr#   c                 4    | j                                         S N)r   r   r    s    r!   r   zSceneGraph.__hash__   s    '')))r#   c                     t                      }t          | j                  |_        t          | j                  |_        |S )z
        Return a copy of the current TransformForest.

        Returns
        ------------
        copied : TransformForest
          Copy of current object.
        )r   r   r   r   )r    copieds     r!   copyzSceneGraph.copy   s6     $T_55$T_55r#   c                     i }| j         }| j        D ]=}||k    r	|                     ||          \  }}|                                |d||<   >|S )z
        Export the current transform graph with all
        transforms baked into world->instance.

        Returns
        ---------
        flat : dict
          Keyed {node : {transform, geometry}
        )r3   r4   )	transformr&   )r   nodesrE   tolist)r    flatr   noder.   r&   s         r!   to_flattenedzSceneGraph.to_flattened   sk     _
J 	N 	NDz!!#xx*xMMFH'-}}HMMDJJr#   c                 D   |0d t          |j                                                  D             }| j        }|j        }|j        }| j        }d|ig}|di|                                D ]2}||k    r	t          |          |<   |                    d|i           3|j	        }	|j
        }
t                      }|D ]}|d         }|
                    |g           }t          |          dk    rfd|D             |d<   d||         v r||         d         }||v r||         |d<   |	r||j        j        k    rd|d	<   ||k    r-|j        |         }|||f         }|d
         }t!          j        |t$                    s/|j                            d                                          |d
<   |                    d          }|r|                                }|                    dd          }t1          |t2                    r9||d<   |                    t          |                                                    }|                    d |                                D                        ||d<   d|i}t          |          dk    rt;          |          |d<   |S )a  
        Export a transforms as the 'nodes' section of the
        GLTF header dict.

        Parameters
        ------------
        scene : trimesh.Scene
          Scene with geometry.
        mesh_index : dict or None
          Mapping { key in scene.geometry : int }

        Returns
        --------
        gltf : dict
          With 'nodes' referencing a list of dicts
        Nc                     i | ]\  }}||	S r(   r(   )r*   inames      r!   r-   z&SceneGraph.to_gltf.<locals>.<dictcomp>   s    RRRga$RRRr#   rf   r   c                      g | ]
}|         S r(   r(   )r*   r+   lookups     r!   rC   z&SceneGraph.to_gltf.<locals>.<listcomp>#  s    #>#>#>!F1I#>#>#>r#   childrenr&   meshcamerar.   r:   r'   gltf_extensions
extensionsc                 ^    i | ]*\  }}t          |d           ||                                +S r_   hasattrr_   r)   s      r!   r-   z&SceneGraph.to_gltf.<locals>.<dictcomp>E  s6    ZZZ41aWQPXEYEYZAHHJJZZZr#   extrasr^   extensionsUsed)	enumerater&   keysr   r2   rF   r   rL   rI   
has_camerari   setrE   rk   rf   parentsr   allcloser@   Treshaper_   r[   pop
isinstancedictunionr7   r/   list)r    scene
mesh_indexgraphr2   rF   r   resultra   rv   ri   extensions_usedinfochildsmesh_keyparent	node_edger.   rr   rm   gltfrh   s                        @r!   to_gltfzSceneGraph.to_gltf   s   $  SR5>;N;N;P;P1Q1QRRRJ O	O	_
 :&'a NN$$ 	* 	*Dz!!v;;F4LMM64.)))) %
>%%  +	, +	,D<D \\$++F6{{Q#>#>#>#>v#>#>#>Z  Yt_,,$T?:6z))#-h#7DL #del&777!"Xz!!t,%vtn5	 #8,}VY77 C%+X%5%5b%9%9%@%@%B%BDN #z22 ,#[[]]F "(,=t!D!DJ!*d33 X-7\**9*?*?JOODUDU@V@V*W*W MMZZ6<<>>ZZZ   &,DN !##%)/%:%:D!"r#   c                 \   | j         j        }g }| j         j                                        D ]~\  }}|\  }}||         }|                                }d|v r|d         |d<   |                    d |                                D                        |                    |||g           |S )z
        Export the current transforms as a list of
        edge tuples, with each tuple having the format:
        (node_a, node_b, {metadata})

        Returns
        ---------
        edgelist : (n,) list
          Of edge tuples
        r&   c                 ^    i | ]*\  }}t          |d           ||                                +S ro   rp   r)   s      r!   r-   z*SceneGraph.to_edgelist.<locals>.<dictcomp>k  s5    TTT41awq(?S?STAHHJJTTTr#   )r   r2   rF   r/   r[   r7   rI   )	r    r^   exportedger6   abb_attrattr_news	            r!   to_edgelistzSceneGraph.to_edgelistN  s     )/399;; 	, 	,JD$DAq 1XFyy{{HV##'-j'9$OOTT8>>+;+;TTT   MM1a*++++r#   Tc                 $   |D ]}t          |          dk    r" | j        |d         |d         fi |d          7t          |          dk    r#|                     |d         |d                    m|rt          dt          |                    dS )aF  
        Load transform data from an edge list into the current
        scene graph.

        Parameters
        -------------
        edgelist : (n,) tuples
          Keyed (node_a, node_b, {key: value})
        strict : bool
          If True raise a ValueError when a
          malformed edge is passed in a tuple.
           r;   r   r   zedge incorrect shape: %sN)rL   r7   
ValueErrorstr)r    edgesstrictr   s       r!   from_edgelistzSceneGraph.from_edgelistp  s      		H 		HD4yyA~~DGT!W88Q8888TaDGT!W---- H !;SYYGGGH		H 		Hr#   c                 f    ddl }|                    |                                 |j                  S )z
        Return a `networkx` copy of this graph.

        Returns
        ----------
        graph : networkx.DiGraph
          Directed graph.
        r   N)create_using)networkxr   r   DiGraph)r    r   s     r!   to_networkxzSceneGraph.to_networkx  s5     	%%d&6&6&8&8xGW%XXXr#   c                     ddl m} ddl}ddi} j        di fd|                                D               |j        dd|                                 i |                                 dS )z
        Plot the scene graph using `networkx.draw_networkx`
        which uses matplotlib to display the graph.

        Parameters
        -----------
        kwargs : dict
          Passed to `networkx.draw_networkx`
        r   Nwith_labelsTc                 $    i | ]\  }}|v	||S r(   r(   )r*   r+   r,   r5   s      r!   r-   z#SceneGraph.show.<locals>.<dictcomp>  s$    NNN$!QavooAooor#   Gr(   )matplotlib.pyplotpyplotr   r7   r/   draw_networkxr   show)r    r5   pltr   defaultss    `   r!   r   zSceneGraph.show  s     	(''''' "4(OONNNN(..*:*:NNNOOO>>!1!1!3!3>v>>>




r#   c                 4    |                      |d           dS )z
        Load transform data from an edge list into the current
        scene graph.

        Parameters
        -------------
        edgelist : (n,) tuples
          Structured (node_a, node_b, {key: value})
        T)r   N)r   )r    edgelists     r!   loadzSceneGraph.load  s#     	8D11111r#   c                     | j         j        S )z
        A list of every node in the graph.

        Returns
        -------------
        nodes : (n,) array
          All node names.
        )r   r^   rX   s    r!   r^   zSceneGraph.nodes  s     $$r#   c                 R    d | j         j                                        D             S )z
        The nodes in the scene graph with geometry attached.

        Returns
        ------------
        nodes_geometry : (m,) array
          Node names which have geometry associated
        c                      g | ]\  }}d |v 	|S )r&   r(   )r*   nr6   s      r!   rC   z-SceneGraph.nodes_geometry.<locals>.<listcomp>  s'    YYYgajTXFXFXFXFXFXr#   )r   r2   r/   rX   s    r!   nodes_geometryzSceneGraph.nodes_geometry  s*     ZY!:!@!@!B!BYYYYr#   c                     t          j        t                    }| j        j                                        D ]*\  }}d|v r!||d                                      |           +|S )z
        Which nodes have this geometry? Inverse
        of `nodes_geometry`.

        Returns
        ------------
        geometry_nodes : dict
          Keyed {geometry_name : node name}
        r&   )collectionsdefaultdictr   r   r2   r/   rI   )r    resra   r6   s       r!   geometry_nodeszSceneGraph.geometry_nodes  sg     %d++/399;; 	3 	3JD$T!!D$%,,T222
r#   
geometriesc                 4   t          |t                    r|g}t          |          }| j        j                                        D ]%}d|v r|d         |v r|                    d           &| j        j                            dd           d| j        _	        dS )z
        Remove the reference for specified geometries
        from nodes without deleting the node.

        Parameters
        ------------
        geometries : list or str
          Name of scene.geometry to dereference.
        r&   r   N)
r}   r   rw   r   r2   valuesr|   r   cache_hash)r    r   attribs      r!   remove_geometrieszSceneGraph.remove_geometries  s     j#&& 	&$J__
 o/6688 	' 	'FV##z(:j(H(H

:&&&
 	.555 $r#   rO   c                     || j         j        v S rW   )r   r2   r    rO   s     r!   __contains__zSceneGraph.__contains__  s    do///r#   c                 ,    |                      |          S rW   )rE   r   s     r!   __getitem__zSceneGraph.__getitem__  s     xx}}r#   valuec                     t          j        |t           j                  }|j        dk    rt	          d          |                     ||          S )Ndtype)r   r   zMatrix must be specified!)r.   )r>   
asanyarrayfloat64shaper   r7   )r    rO   r   s      r!   __setitem__zSceneGraph.__setitem__  sJ    e2:666;&  8999{{3u{---r#   c                 ^    t                      | _        | j                                         d S rW   )r   r   r   clearrX   s    r!   r   zSceneGraph.clear
  s)    (**r#   )r   r   rW   )T)&__name__
__module____qualname____doc__r"   r7   r   r   r   r   r>   r   rE   r   r[   rb   r   r   r   r   r   r   r   cache_decoratorr^   r   r   r   r   rw   r   r   boolr   r   r   r   r   r(   r#   r!   r   r      sY        3 3 3 34*Q *Q *Q *QZ DH^  ^  ^ .6x.@^ 	wrz"HX$66	7^  ^  ^  ^ @* * *    ,e e e eN     DH H H H4Y Y Y  *
2 
2 
2 	% 	% 	% 	Z 	Z 	Z    %E#sH2D,E % % % %60 0T 0 0 0 0	wrz"HX$66	7   
.x .	 . . . .    r#   r   c                   b    e Zd ZdZd Zd Zd Zd Zed             Z	ed             Z
d Zd	 Zd
S )r   a  
    A simple forest graph data structure: every node
    is allowed to have exactly one parent. This makes
    traversal and implementation much simpler than a
    full graph data type; by storing only one parent
    reference, it enforces the structure for "free."
    c                     i | _         t          j        t                    | _        t          j        t                    | _        i | _        d S rW   )rx   r   r   r~   rF   r2   r   rX   s    r!   r"   zEnforcedForest.__init__  s>    
  %066$066 r#   c                 J   d| _         ||f| j        vri | _        n| j        ||f         }t          j        |                    dt                    |                    dt                    d          r.|                    d          |                    d          k    rdS || j        |<   || j        ||f<   | j        |         	                    i            d|v r)| j        |         	                    d|d         i           n | j        |         	                    i            dS )aa  
        Add an edge to the forest cleanly.

        Parameters
        -----------
        u : any
          Hashable node key.
        v : any
          Hashable node key.
        kwargs : dict
           Stored as (u, v) edge data.

        Returns
        --------
        changed : bool
          Return if this operation changed anything.
        Nr.   r=   r&   FT)
r   rF   r   r   ry   rE   r@   rx   r2   r7   )r    rS   r,   r5   r   s        r!   r1   zEnforcedForest.add_edge)  s$   $ 
 q6''DKK >1a&)D}

8Y//(I1N1NPT  88J''6::j+A+AAAu Q!'1vq  $$$N1$$j&2D%EFFFFN1$$R(((tr#   c                    | j         vrdS i | _        d| _        fd| j                                        D             }|D ]
}| j        |= | j        v r| j        = fd| j        D             }|D ]
}| j        |= | j         = dS )z
        Remove a node from the forest.

        Parameters
        -----------
        u : any
          Hashable node key.

        Returns
        --------
        changed : bool
          Return if this operation changed anything.
        FNc                 &    g | ]\  }}|k    |S r(   r(   )r*   childr   rS   s      r!   rC   z.EnforcedForest.remove_node.<locals>.<listcomp>l  s#    UUUoufSTEr#   c                 6    g | ]\  }}|k    s|k    ||fS r(   r(   )r*   r   r   rS   s      r!   rC   z.EnforcedForest.remove_node.<locals>.<listcomp>s  s.    IIIFQQ!q&&!Q&&&r#   T)r2   r   r   rx   r/   rF   )r    rS   ri   cr   es    `    r!   remove_nodezEnforcedForest.remove_nodeU  s     DN""5 
 VUUU1C1C1E1EUUU 	  	 AQQ JIIIdnIII 	" 	"Aq!! N1tr#   c                    ||k    rg S ||f| j         v r| j         ||f         S ||f| j         v r| j         ||f         ddd         S | j        }|g}|g}t          t          |          dz             D ]}|                    |d                   }|                    |d                   }|                    |           |                    |           ||k    r|| j         ||f<   |c S ||k    r|ddd         }|| j         ||f<   |c S ||v s|*|'t          |                              |                              dh          t                    dk    rt          d| d| d          t                    dk    r"t          fd|D                       }	|	v sJ nt          t                              }	|d|                    |	          dz            }
|d|                    |	                   }|
|ddd         z   }|d         |k    sJ |d         |k    sJ || j         ||f<   |c S t          d	          )
a  
        Find the shortest path between `u` and `v`, returning
        a path where the first element is always `u` and the
        last element is always `v`, disregarding edge direction.

        Parameters
        -----------
        u : any
          Hashable node key.
        v : any
          Hashable node key.

        Returns
        -----------
        path : (n,)
          Path between `u` and `v`
        Nr:   r;   r   zNo path from z->!c              3   $   K   | ]
}|v |V  d S rW   r(   )r*   fcommons     r!   	<genexpr>z/EnforcedForest.shortest_path.<locals>.<genexpr>  s'      BBaa6kkkkkkBBr#   zIteration limit exceeded!)r   rx   rangerL   rE   rI   rw   intersection
differencer   nextiterindex)r    rS   r,   rx   rT   rU   _r   r   linkr   rQ   r   s               @r!   rG   zEnforcedForest.shortest_path|  s   & 66IVt{"";1v&&Vt{"";1v&ttt,, ,#3 s7||a'(( )	 )	AGBK((AHRL))ANN1OOAAvv&-QF#a#DDbD>&.QF#w,,AI!) X33G<<GGOOv;;!##$%>Q%>%>!%>%>%>???[[1__BBBB7BBBBBD6>>>>>  V--D 5gmmD11A5563x~~d33341TTrT7{ Aw!||||Bx1}}}}&*QF#4555r#   c                 4    | j                                         S )z
        Get a set of every node.

        Returns
        -----------
        nodes : set
          Every node currently stored.
        )r2   ru   rX   s    r!   r^   zEnforcedForest.nodes  s     ~""$$$r#   c                     d| j         v r| j         d         S t          j        t                    fd| j                                        D              t                    | j         d<   | j         d         S )z
        Get the children of each node.

        Returns
        ----------
        children : dict
          Keyed {node : [child, child, ...]}
        ri   c                 X    g | ]&\  }}||k    |                              |          'S r(   )rI   )r*   rS   r,   r   s      r!   rC   z+EnforcedForest.children.<locals>.<listcomp>  s2    GGG1Qq		r#   )r   r   r   r   rx   r/   r~   )r    r   s    @r!   ri   zEnforcedForest.children  s{     $$;z**'-- 	HGGG(:(:(<(<GGGG #'u++J{:&&r#   c                 h   | j         }||vr|hS |g}t          |          }t          t          | j                  dz             D ]l}t          |          dk    r|c S |                    |                                          }|*|                    |           |                    |           m|S )a8  
        Get all nodes that are successors to specified node,
        including the specified node.

        Parameters
        -------------
        node : any
          Hashable key for a node.

        Returns
        ------------
        successors : set
          Nodes that succeed specified node.
        r;   r   )	ri   rw   r   rL   r2   rE   r|   extendr7   )r    ra   ri   queue	collectedr   r   s          r!   
successorszEnforcedForest.successors  s      =x6M JJ	 s4>**Q.// 	) 	)A5zzQ    \\%))++..F!V$$$  (((r#   c                    t          | dd          }||S t          d                    d | j                                        D                       d                    d | j                                        D                       z                       d          d                    d | j                                        D                       z             }|| _        |S )	ao  
        Actually hash all of the data, but use a "dirty" mechanism
        in functions that modify the data, which MUST
        # all invalidate the hash by setting `self._hash = None`

        This was optimized a bit, and is evaluating on an
        older laptop on a scene with 77 nodes and 76 edges
        10,000 times in 0.7s which seems fast enough.
        r   N c              3      K   | ]:\  }}t          t          |                    |                    d d          z   V  ;dS r&   r   N)r   hashrE   r)   s      r!   r   z*EnforcedForest.__hash__.<locals>.<genexpr>(  sY        1 QLL155R#8#88     r#   c              3   h   K   | ]-\  }}t          |          |                    d d          z   V  .dS r   )r   rE   r)   s      r!   r   z*EnforcedForest.__hash__.<locals>.<genexpr>,  sP        7;q!CFFQUU:r222     r#   zutf-8r#   c              3   R   K   | ]"}d |v |d                                           V  #dS )r.   N)tobytes)r*   r,   s     r!   r   z*EnforcedForest.__hash__.<locals>.<genexpr>0  s@        *+(VW--(##%%---- r#   )	getattrr   joinrF   r/   r2   encoder   r   )r    hasheds     r!   r   zEnforcedForest.__hash__  s    w--M   $ 4 4 6 6     ''  ?C~?S?S?U?U    	 fWoohh  /3~/D/D/F/F    
 
 
r#   N)r   r   r   r   r"   r1   r   rG   propertyr^   ri   r   r   r(   r#   r!   r   r     s           "* * *X% % %NN6 N6 N6` 	% 	% X	% ' ' X'($ $ $L" " " " "r#   r   c                     |  t          j        | t           j                  S |t          |          } n)||t	          ||          } nt          j        d          } || dddfxx         |z  cc<   | S )z
    Take multiple keyword arguments and parse them
    into a homogeneous transformation matrix.

    Returns
    ---------
    matrix : (4, 4) float
      Homogeneous transformation matrix.
    Nr   r   r   )r>   arrayr   r	   r
   eye)r.   
quaterniontranslationaxisangler5   s         r!   r0   r0   8  s     xbj1111		":..		e/ -- 	rr1u$Mr#   )NNNNN)r   r[   r   numpyr>   r   r   r   r   transformationsr   r	   r
   typedr   r   r   r   r   r   r   r  r@   rN   r   r   r0   r(   r#   r!   <module>r     sQ                               K K K K K K K K K K R R R R R R R R R R R R R R R R R R BF1II	$	 | | | | | | | |~f f f f f f f fT	 FJ     r#   