Ë
    :vžj
q  ã                   óì   — d dl Z 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  ej(                  d«      Zd	ej,                  d
<   dZ G d„ d«      Z G d„ d«      Z	 dd„Zy)é    N)Údeepcopyé   )ÚcachingÚutil)Ú	hash_fast)Ú	fix_rigidÚquaternion_matrixÚrotation_matrix)Ú	ArrayLikeÚFloatingÚHashableÚNDArrayÚSequenceé   FÚ	WRITEABLEÚworldc            
       óž  — e Zd ZdZ	 ddedz  dedz  fd„Zd d„Z	 d dededz  d	ee	e
j                     edz  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z  ez  fd„Zded	efd„Z ded	ee	e
j                     edz  f   fd„Z!dede"fd„Z#d„ Z$y)"Ú
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.
    NÚ
base_frameÚrepair_rigidc                 ó–   — t        «       | _        |�|nt        | _        || _        t        j                  | j                  «      | _        y)a!  
        Create a scene graph, holding homogeneous transformation
        matrices and instance information about geometry.

        Parameters
        -----------
        base_frame
          The root node transforms will be positioned from.
        repair_rigid
          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ÚDEFAULT_BASE_FRAMEr   r   r   ÚCacheÚ__hash__Ú_cache)Úselfr   r   s      úi/workspace/moltex-experiments/.pixi/envs/default/lib/python3.12/site-packages/trimesh/scene/transforms.pyÚ__init__zSceneGraph.__init__   s=   € ô( )Ó*ˆŒð )3Ð(>™*ÔDVˆŒð )ˆÔä—m‘m D§M¡MÓ2ˆ�ó    c                 ó  — |€| j                   }|j                  «       D ��ci c]  \  }}|dv sŒ||“Œ }}}t        di |¤Ž|d<    | j                  j                  ||fi |¤Ž d|v r |d   | j                  j
                  |   d<   yyc c}}w )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').
        N>   ÚgeometryÚmetadataÚmatrixr#   © )r   ÚitemsÚkwargs_to_matrixr   Úadd_edgeÚ	node_data)r   Úframe_toÚ
frame_fromÚkwargsÚkÚvÚattrs          r   ÚupdatezSceneGraph.update;   s    € ð8 ÐØŸ™ˆJð "(§¡¤ÔQ¡™˜˜A°1Ð8PÒ3P��1‘ ˆÑQä)Ñ3¨FÑ3ˆˆX‰ð 	!ˆ�‰× Ñ  ¨XÑ>¸Ò>ð ˜ÑØ>DÀZÑ>PˆD�O‰O×%Ñ% hÑ/°
Ò;ð  ùó Rs
   ¢B¯Br+   r,   Úreturnc                 ó  — |€| j                   }||f}|| j                  v r| j                  |   S | j                  j                  |   j	                  d«      }| j                  j
                  }||k(  rt        }�nC||v r
||   d   }�n5| j                  j                  ||«      }|d   |k(  sJ ‚|d   |k(  sJ ‚g }t        j                  |«      D ]p  \  }	}
|j	                  |	|
f«      }|�d|v r|j                  |d   «       Œ4||
|	f   }d|v sŒ@|j                  t        j                  j                  |d   «      «       Œr |D �cg c]2  }t        j                  |t        z
  «      j                  «       dkD  sŒ1|‘Œ4 }}t!        |«      dk(  rt        }n)t!        |«      dk(  r|d   }nt#        j$                  |«      }| j&                  �t)        || j&                  ¬«      }d|j*                  d	<   ||f| j                  |<   ||fS c c}w )
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.
        r#   r%   r   éÿÿÿÿç:Œ0âŽyE>é   )Úmax_devianceFr   )r   r   r   r*   ÚgetÚ	edge_dataÚ	_identityÚshortest_pathÚ	itertoolsÚpairwiseÚappendÚnpÚlinalgÚinvÚabsÚmaxÚlenr   Ú	multi_dotr   r   Úflags)r   r+   r,   Úkeyr#   Údatar%   ÚpathÚmatricesÚur/   ÚforwardÚbackwardÚms                 r   r8   zSceneGraph.getg   s  € ð8 ÐØŸ™ˆJð ˜8Ð$ˆØ�$—+‘+ÑØ—;‘;˜sÑ#Ð#ð —?‘?×,Ñ,¨XÑ6×:Ñ:¸:ÓFˆð �‰×(Ñ(ˆà˜Ò!äŠFØ�D‰[à˜#‘Y˜xÑ(ŠFð
 —?‘?×0Ñ0°¸XÓFˆDà˜‘7˜jÒ(Ð(Ð(à˜‘8˜xÒ'Ð'Ð'ð ˆHÜ!×*Ñ*¨4Ö0‘��1ØŸ(™( A q 6Ó*�ØÐ&Ø 7Ñ*à Ÿ™¨°Ñ(9Ô:Øð    A ™<�Ø˜xÒ'à—O‘O¤B§I¡I§M¡M°(¸8Ñ2DÓ$EÕFð 1ñ $,ÓR¡8˜a¬r¯v©v°a¼)±mÓ/D×/HÑ/HÓ/JÈTÓ/Qš 8ˆHÐRÜ�8‹} Ò!Ü"‘Ü�X“ !Ò#Ø! !™‘ô Ÿ™¨Ó1�ð ×ÑÐ(Ü˜v°D×4EÑ4EÔFˆFð %*ˆ�‰�[Ñ!ð # HÐ-ˆ�‰�CÑà�xÐÐùò' Ss   Å2HÅ:Hc                 ó6   — | j                   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Ê   s2   € ô “ˆÜ$ T§_¡_Ó5ˆÔÜ$ T§_¡_Ó5ˆÔØˆr!   c                 ó¨   — i }| j                   }| j                  D ]4  }||k(  rŒ	| j                  ||¬«      \  }}|j                  «       |dœ||<   Œ6 |S )zÑ
        Export the current transform graph with all
        transforms baked into world->instance.

        Returns
        ---------
        flat : dict
          Keyed {node : {transform, geometry}
        )r+   r,   )Ú	transformr#   )r   Únodesr8   Útolist)r   Úflatr   Únoder%   r#   s         r   Úto_flattenedzSceneGraph.to_flattenedÙ   s]   € ð ˆØ—_‘_ˆ
Ø—J”JˆDØ�zÒ!Øà#Ÿx™x°À*˜xÓMÑˆF�Hà'-§}¡}£ÀHÑMˆD�ŠJð ð ˆr!   c                 ó\  — |€6t        |j                  j                  «       «      D ��ci c]  \  }}||“Œ
 }}}| j                  }|j                  }|j
                  }| j                  }|j                  }	|j                  }
d|j                  |i «      vxr> |	xr ||j                  j                  k(   xr t        |
j                  |g «      «      dkD  }|rg }i }n	d|ig}|di}|j                  «       D ])  }||k(  rŒ	t        |«      ||<   |j                  d|i«       Œ+ t        «       }|D �]¦  }|d   }|
j                  |g «      }t        |«      dkD  r|D �cg c]  }||   ‘Œ	 c}|d<   d||   v r||   d   }||v r||   |d<   |	r||j                  j                  k(  rd|d<   ||k7  sŒ€|j                  |   }|||f   }|d   }t!        j"                  |t$        «      s,|j&                  j)                  d	«      j+                  «       |d<   |j                  d
«      }|sŒõ|j-                  «       }|j/                  dd«      }t1        |t2        «      r-||d<   |j5                  t        |j                  «       «      «      }|j7                  |j9                  «       D ��ci c]#  \  }}t;        |d«      sŒ||j+                  «       “Œ% c}}«       ||d<   �Œ© |r|
|   D �cg c]  }||   ‘Œ	 }}n||   g}||dœ}t        |«      dkD  rt=        |«      |d<   |S c c}}w c c}w c c}}w c c}w )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 and 'scene_roots'
          referencing the node indices the scene should start from.
        Nr#   r   ÚnameÚchildrenÚmeshÚcamerar%   r4   r$   Úgltf_extensionsÚ
extensionsrX   Úextras)rW   Úscene_rootsÚextensionsUsed)Ú	enumerater#   Úkeysr   r*   r9   r   Ú
has_camerar^   r8   r`   r]   rD   r>   ÚsetÚparentsr   Úallcloser:   ÚTÚreshaperX   rT   ÚpopÚ
isinstanceÚdictÚunionr1   r'   ÚhasattrÚlist)r   ÚsceneÚ
mesh_indexÚir]   Úgraphr*   r9   r   rh   r^   Ú	skip_baseÚresultÚlookuprZ   Úextensions_usedÚinfoÚchildsr.   Úmesh_keyÚparentÚ	node_edger%   rc   rb   r/   ÚcÚrootsÚgltfs                                r   Úto_gltfzSceneGraph.to_gltfï   sT  € ð& Ðô 2;¸5¿>¹>×;NÑ;NÓ;PÔ1QÔRÑ1Q¡g a¨˜$ ™'Ð1QˆJÑRð —‘ˆà—O‘Oˆ	Ø—O‘Oˆ	Ø—_‘_ˆ
à×%Ñ%ˆ
Ø—>‘>ˆð ˜iŸm™m¨J¸Ó;Ð;ò 6ØÒC J°%·,±,×2CÑ2CÑ$CÐDò6ä�H—L‘L ¨RÓ0Ó1°AÑ5ð 	ñ ØˆFØ‰Fà˜zÐ*Ð+ˆFØ  !�_ˆFð —N‘NÖ$ˆDØ�zÒ!Øä˜v›;ˆF�4‰Là�M‰M˜6 4˜.Õ)ð %ô ›%ˆô ˆDà˜‘<ˆDð —\‘\ $¨Ó+ˆFÜ�6‹{˜QŠÙ7=Ó#>±v°! F¨1£I°vÑ#>��ZÑ ð ˜Y t™_Ñ,Ø$ T™?¨:Ñ6�Ø˜zÑ)Ø#-¨hÑ#7�D˜‘Lá˜d e§l¡l×&7Ñ&7Ò7Ø!"��X‘à�zÓ!ØŸ™ tÑ,�Ø% v¨t nÑ5�	ð # 8Ñ,�ä—}‘} V¬YÔ7Ø%+§X¡X×%5Ñ%5°bÓ%9×%@Ñ%@Ó%B�D˜‘Nð #Ÿ™ zÓ2�ÚØ#Ÿ[™[›]�Fð "(§¡Ð,=¸tÓ!D�JÜ! *¬dÔ3Ø-7˜˜\Ñ*Ø*9×*?Ñ*?ÄÀJÇOÁOÓDUÓ@VÓ*W˜ð —M‘MØ39·<±<´>ÔZ±>©4¨1¨aÄWÈQÐPXÕEY˜˜AŸH™H›J™°>ÒZôð &,�D˜“NðW ñZ Ø(0°Ò(<Ó=Ñ(< 1�V˜A“YÐ(<ˆEÑ=à˜JÑ'Ð(ˆEà°Ñ6ˆÜˆÓ !Ò#Ü%)¨/Ó%:ˆDÐ!Ñ"ØˆùóA Sùòd $?ùóD [ùò
 >s   ©LÅLÊL#Ê4L#Ë L)c                 óª  — | j                   j                  }g }| j                   j                  j                  «       D ]�  \  }}|\  }}||   }|j	                  «       }d|v r|d   |d<   |j                  |j                  «       D �	�
ci c]#  \  }	}
t        |
d«      sŒ|	|
j                  «       “Œ% c}
}	«       |j                  |||g«       Œ� |S c c}
}	w )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#   rX   )	r   r*   r9   r'   rT   r1   rr   rX   r>   )r   rW   ÚexportÚedger0   ÚaÚbÚb_attrÚattr_newr.   r/   s              r   Úto_edgelistzSceneGraph.to_edgelistg  sÏ   € ð —‘×)Ñ)ˆàˆàŸ/™/×3Ñ3×9Ñ9Ö;‰JˆD�$à‰DˆAˆqð ˜1‘XˆFà—y‘y“{ˆHà˜VÑ#Ø'-¨jÑ'9�˜Ñ$à�O‰OØ+3¯>©>Ô+;ÔTÑ+;¡4 1 a¼wÀqÈ(Õ?S��A—H‘H“J‘Ð+;ÒTôð �M‰M˜1˜a Ð*Õ+ð <ð  ˆùó Us   ÂCÂCc                 óæ   — |D ]l  }t        |«      dk(  r | j                  |d   |d   fi |d   ¤Ž Œ/t        |«      dk(  r| j                  |d   |d   «       ŒV|sŒYt        dt        |«      «      ‚ y)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.
        é   r6   r   r   zedge incorrect shape: %sN)rD   r1   Ú
ValueErrorÚstr)r   ÚedgesÚstrictr‡   s       r   Úfrom_edgelistzSceneGraph.from_edgelist‰  sp   € ó ˆDä�4‹y˜AŠ~Ø�—‘˜D ™G T¨!¡WÑ8°°Q±Ó8ä�T“˜a’Ø—‘˜D ™G T¨!¡WÕ-âÜ Ð!;¼SÀ»YÓGÐGñ r!   c                 ó`   — ddl }|j                  | j                  «       |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£  s,   € ó 	à×%Ñ% d×&6Ñ&6Ó&8Àx×GWÑGWÐ%ÓXÐXr!   c           
      ó  — ddl m} ddl}ddi} |j                  di |j	                  «       D ��ci c]  \  }}||vsŒ||“Œ c}}¤Ž  |j
                  dd| j                  «       i|¤Ž |j                  «        yc c}}w )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_labelsTÚGr&   )Úmatplotlib.pyplotÚpyplotr–   r1   r'   Údraw_networkxr˜   Úshow)r   r-   Úpltr–   Údefaultsr.   r/   s          r   rŸ   zSceneGraph.show°  s}   € õ 	(Ûð " 4Ð(ˆØˆ�‰ÑO¨(¯.©.Ô*:ÔNÑ*:¡$ ! Q¸aÀvºo˜˜A™Ð*:ÒNÒOØˆ×ÑÑ> ×!1Ñ!1Ó!3Ð>°vÒ>à�‰�
ùó Os
   °A;½A;c                 ó*   — | j                  |d¬«       y)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   € ð 	×Ñ˜8¨DÐÕ1r!   c                 ó.   — | j                   j                  S )z�
        A list of every node in the graph.

        Returns
        -------------
        nodes : (n,) array
          All node names.
        )r   rW   rQ   s    r   rW   zSceneGraph.nodesÑ  s   € ð �‰×$Ñ$Ð$r!   c                 ó†   — | j                   j                  j                  «       D ��cg c]  \  }}d|v sŒ|‘Œ c}}S c c}}w )zÄ
        The nodes in the scene graph with geometry attached.

        Returns
        ------------
        nodes_geometry : (m,) array
          Node names which have geometry associated
        r#   )r   r*   r'   )r   Únr0   s      r   Únodes_geometryzSceneGraph.nodes_geometryÝ  s=   € ð "&§¡×!:Ñ!:×!@Ñ!@Ô!BÔYÑ!B‘g�a˜ÀjÐTXÒFX’Ð!BÒYÐYùÓYs   ¨=µ=c                 óÈ   — t        j                  t        «      }| j                  j                  j                  «       D ]!  \  }}d|v sŒ||d      j                  |«       Œ# |S )zÆ
        Which nodes have this geometry? Inverse
        of `nodes_geometry`.

        Returns
        ------------
        geometry_nodes : dict
          Keyed {geometry_name : node name}
        r#   )ÚcollectionsÚdefaultdictrs   r   r*   r'   r>   )r   ÚresrZ   r0   s       r   Úgeometry_nodeszSceneGraph.geometry_nodesé  s\   € ô ×%Ñ%¤dÓ+ˆØŸ/™/×3Ñ3×9Ñ9Ö;‰JˆD�$Ø˜TÒ!Ø�D˜Ñ$Ñ%×,Ñ,¨TÕ2ð <ð ˆ
r!   Ú
geometriesc                 ó<  — t        |t        «      r|g}t        |«      }| j                  j                  j                  «       D ]   }d|v sŒ|d   |v sŒ|j                  d«       Œ" | j                  j                  j                  dd«       d| j                  _	        y)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)
ro   r�   ri   r   r*   Úvaluesrn   r   ÚcacheÚ_hash)r   r®   Úattribs      r   Úremove_geometrieszSceneGraph.remove_geometriesú  s†   € ô �j¤#Ô&Ø$˜ˆJÜ˜“_ˆ
ð —o‘o×/Ñ/×6Ñ6Ö8ˆFØ˜VÒ#¨¨zÑ(:¸jÒ(HØ—
‘
˜:Õ&ð 9ð 	�‰×Ñ×ÑÐ.°Ô5Ø $ˆ�‰Õr!   rG   c                 ó2   — || j                   j                  v S rP   )r   r*   ©r   rG   s     r   Ú__contains__zSceneGraph.__contains__  s   € Ø�d—o‘o×/Ñ/Ð/Ð/r!   c                 ó$   — | j                  |«      S rP   )r8   r¶   s     r   Ú__getitem__zSceneGraph.__getitem__  s   € Ø�x‰x˜‹}Ðr!   Úvaluec                 ó¦   — t        j                  |t         j                  ¬«      }|j                  dk7  rt	        d«      ‚| j                  ||¬«      S )N©Údtype)r   r   zMatrix must be specified!)r%   )r?   Ú
asanyarrayÚfloat64Úshaper�   r1   )r   rG   rº   s      r   Ú__setitem__zSceneGraph.__setitem__  sA   € Ü—‘˜e¬2¯:©:Ô6ˆØ�;‰;˜&Ò ÜÐ8Ó9Ð9Ø�{‰{˜3 uˆ{Ó-Ð-r!   c                 óV   — t        «       | _        | j                  j                  «        y rP   )r   r   r   ÚclearrQ   s    r   rÃ   zSceneGraph.clear!  s   € Ü(Ó*ˆŒØ�‰×ÑÕr!   )Ngñhãˆµøä>rP   )T)%Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r    r1   Útupler   r?   r¿   r8   r   rT   r[   r„   rŒ   r“   r˜   rŸ   r¤   r   Úcache_decoratorrW   r¨   r­   r�   ri   r   r´   Úboolr·   r¹   r   rÁ   rÃ   r&   r!   r   r   r      sc  „ ñð SWñ3Ø" T™/ð3Ø@HÈ4Áó3ó<*QðZ AEñ^ Ø ð^ Ø.6¸©oð^ à	ˆw�r—z‘zÑ" H¨t¡OÐ3Ñ	4ó^ ò@*òòó,vòp óDHò4Yòò*
2ð ×Ññ	%ó ð	%ð ×Ññ	Zó ð	Zð ×Ññó ðð %¨C°#©I¸Ñ,@ó %ð60 ð 0¨Tó 0ð˜xð ¨E°'¸"¿*¹*Ñ2EÀxÐRVÁÐ2VÑ,Wó ð.˜xð .°	ó .ór!   r   c                   óT   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zed„ «       Z	ed„ «       Z
d„ Zd	„ Zy
)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 | _        y rP   )rj   rª   r«   rp   r9   r*   r   rQ   s    r   r    zEnforcedForest.__init__/  s:   € ð
 ˆŒô %×0Ñ0´Ó6ˆŒä$×0Ñ0´Ó6ˆŒð ˆ�r!   c                 ó2  — d| _         ||f| j                  vri | _        nt| j                  ||f   }t        j                  |j                  dt        «      |j                  dt        «      d«      r$|j                  d«      |j                  d«      k(  ry|| j                  |<   || j                  ||f<   | j                  |   j                  i «       d|v r$| j                  |   j                  d|d   i«       y| j                  |   j                  i «       y)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%   r5   r#   FT)
r²   r9   r   r   rk   r8   r:   rj   r*   r1   )r   rK   r/   r-   r‡   s        r   r)   zEnforcedForest.add_edge@  s  € ð$ ˆŒ
ð ˆqˆ6˜Ÿ™Ñ'ØˆD�Kð —>‘> 1 a &Ñ)ˆDÜ�}‰}Ø—
‘
˜8¤YÓ/°·±¸(ÄIÓ1NÐPTôà—8‘8˜JÓ'¨6¯:©:°jÓ+AÒAØð ˆ�‰�Q‰à!'ˆ�‰˜˜1�vÑà�‰�qÑ× Ñ  Ô$Ø˜ÑØ�N‰N˜1Ñ×$Ñ$ j°&¸Ñ2DÐ%EÔFð ð �N‰N˜1Ñ×$Ñ$ RÔ(àr!   c                 ó°  — || j                   vryi | _        d| _        | j                  j	                  «       D ��cg c]  \  }}||k(  sŒ|‘Œ }}}|D ]  }| j                  |= Œ || j                  v r| j                  |= | j
                  D ��cg c]  \  }}||k(  s||k(  sŒ||f‘Œ }}}|D ]  }	| j
                  |	= Œ | j                   |= yc c}}w c c}}w )zó
        Remove a node from the forest.

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

        Returns
        --------
        changed : bool
          Return if this operation changed anything.
        FNT)r*   r   r²   rj   r'   r9   )
r   rK   Úchildr   r^   r�   rˆ   r‰   r‘   Úes
             r   Úremove_nodezEnforcedForest.remove_nodel  sà   € ð �D—N‘NÑ"Øð ˆŒØˆŒ
ð 26·±×1CÑ1CÔ1EÔUÑ1E™o˜u fÈÐSTË’EÐ1EˆÑUÛˆAØ—‘˜Q‘ð à�—‘ÑØ—‘˜Q�ð '+§n¢nÔI¡n™F˜Q ¸¸QºÀ!ÀqÃ&�!�Q’ nˆÑIÛˆAØ—‘˜qÑ!ð ð �N‰N˜1Ðàùó Vùó Js   »CÁ	CÂCÂ!C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 �]v  }|j	                  |d   «      }|j	                  |d   «      }|j                  |«       |j                  |«       ||k(  r|| j                   ||f<   |c S ||k(  r|ddd…   }|| j                   ||f<   |c S ||v s|�Œ‘|�Œ”t        |«      j                  |«      j                  dh«      Št        ‰«      dk(  rt        d|› d|› d�«      ‚t        ‰«      dkD  rt        ˆfd„|D «       «      }	|	‰v sJ ‚t        t        ‰«      «      }	|d|j                  |	«      dz    }
|d|j                  |	«       }|
|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`
        Nr4   r6   r   zNo path from z->Ú!c              3   ó,   •K  — | ]  }|‰v sŒ|–— Œ y ­wrP   r&   )Ú.0ÚfÚcommons     €r   Ú	<genexpr>z/EnforcedForest.shortest_path.<locals>.<genexpr>Î  s   øè ø€ ÐB©7 a°a¸6²k¤©7ùs   ƒ	�zIteration limit exceeded!)r   rj   ÚrangerD   r8   r>   ri   ÚintersectionÚ
differencer�   ÚnextÚiterÚindex)r   rK   r/   rj   rL   rM   Ú_rÖ   r‰   Úlinkrˆ   rI   r×   s               @r   r;   zEnforcedForest.shortest_path“  s4  ø€ ð& �Š6àˆIØ�ˆV�t—{‘{Ñ"à—;‘;  1˜vÑ&Ð&Ø�ˆV�t—{‘{Ñ"Ø—;‘;  1˜vÑ&¡t¨ tÑ,Ð,ð —,‘,ˆà�#ˆØ�3ˆô ”s˜7“| aÑ'×(ˆAà—‘˜G B™KÓ(ˆAØ—‘˜H R™LÓ)ˆAØ�N‰N˜1ÔØ�O‰O˜AÔà�AŠvØ&-�—‘˜Q ˜FÑ#Ø’Ø�a’à#¡D b D™>�Ø&.�—‘˜Q ˜FÑ#Ø’Ø�w‘, A¡I°!±)ô ˜X›×3Ñ3°GÓ<×GÑGÈÈÓO�Ü�v“; !Ò#Ü$ }°Q°C°r¸!¸¸AÐ%>Ó?Ð?Ü˜“[ 1’_äÓB©7ÓBÓB�DØ 6™>Ð)˜>ô  ¤ V£Ó-�Dð Ð5˜gŸm™m¨DÓ1°AÑ5Ð6�ØÐ3˜xŸ~™~¨dÓ3Ð4�Ø˜1™T˜r˜T™7‘{�ð ˜A‘w !’|Ð#�|Ø˜B‘x 1’}Ð$�}à&*�—‘˜Q ˜FÑ#à’ðS )ôV Ð4Ó5Ð5r!   c                 ó6   — | j                   j                  «       S )zŠ
        Get a set of every node.

        Returns
        -----------
        nodes : set
          Every node currently stored.
        )r*   rg   rQ   s    r   rW   zEnforcedForest.nodesã  s   € ð �~‰~×"Ñ"Ó$Ð$r!   c                 óR  — d| j                   v r| j                   d   S t        j                  t        «      }| j                  j                  «       D ��cg c]  \  }}||k7  sŒ||   j                  |«      ‘Œ! c}} t        |«      | j                   d<   | j                   d   S c c}}w )z™
        Get the children of each node.

        Returns
        ----------
        children : dict
          Keyed {node : [child, child, ...]}
        r^   )r   rª   r«   rs   rj   r'   r>   rp   )r   rÏ   rK   r/   s       r   r^   zEnforcedForest.childrenï  s’   € ð ˜Ÿ™Ñ$Ø—;‘;˜zÑ*Ð*Ü×'Ñ'¬Ó-ˆð )-¯©×(:Ñ(:Ô(<ÔGÑ(<¡  1ÀÀQÃˆˆq‰�‰˜Õ	Ð(<ÓGô #' u£+ˆ�‰�JÑØ�{‰{˜:Ñ&Ð&ùó	 	Hs   ÁB#Á"B#c                 ó@  — | j                   }||vr|hS |g}t        |«      }t        t        | j                  «      dz   «      D ]X  }t        |«      dk(  r|c S |j                  |j                  «       «      }|€Œ7|j                  |«       |j                  |«       ŒZ |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.
        r6   r   )	r^   ri   rÙ   rD   r*   r8   rn   Úextendr1   )r   rZ   r^   ÚqueueÚ	collectedrß   r}   s          r   Ú
successorszEnforcedForest.successors  sš   € ð  —=‘=ˆà�xÑØ�6ˆMð �ˆä˜“Jˆ	ô ”s˜4Ÿ>™>Ó*¨QÑ.Ö/ˆAÜ�5‹z˜QŠà Ò à—\‘\ %§)¡)£+Ó.ˆFØÑ!Ø—‘˜VÔ$Ø× Ñ  Õ(ð 0ð Ðr!   c                 óŠ  — t        | dd«      }|�|S t        dj                  d„ | j                  j	                  «       D «       «      dj                  d„ | j
                  j	                  «       D «       «      z   j                  d«      dj                  d„ | j                  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   óp   K  — | ].  \  }}t        t        |«      «      |j                  d d«      z   –— Œ0 y­w©r#   ré   N)r�   Úhashr8   ©rÕ   r.   r/   s      r   rØ   z*EnforcedForest.__hash__.<locals>.<genexpr>?  s4   è ø€ ð á 6™˜˜1ô œ˜Q›“L 1§5¡5¨°RÓ#8Õ8Ù 6ùs   ‚46c              3   ó^   K  — | ]%  \  }}t        |«      |j                  d d«      z   –— Œ' y­wrë   )r�   r8   rí   s      r   rØ   z*EnforcedForest.__hash__.<locals>.<genexpr>C  s-   è ø€ ð Ù?U±t°q¸!”C˜“F˜QŸU™U :¨rÓ2Õ2Ñ?Uùs   ‚+-zutf-8r!   c              3   óL   K  — | ]  }d |v sŒ|d    j                  «       –— Œ y­w)r%   N)Útobytes)rÕ   r/   s     r   rØ   z*EnforcedForest.__hash__.<locals>.<genexpr>G  s)   è ø€ ð Ù/F¨!È(ÐVWÊ-��(‘×#Ñ#×%Ñ/Fùs   ‚	$Œ$)	Úgetattrr   Újoinr9   r'   r*   Úencoder°   r²   )r   Úhasheds     r   r   zEnforcedForest.__hash__*  s¾   € ô ˜˜w¨Ó-ˆØÐØˆMäà—‘ñ à $§¡× 4Ñ 4Ô 6óó ð —'‘'ñ Ø?C¿~¹~×?SÑ?SÔ?Uóó ñ	÷ ‰f�W‹oØ�h‰hñ Ø/3¯~©~×/DÑ/DÔ/Fóó ñó
ˆð ˆŒ
Øˆr!   N)rÄ   rÅ   rÆ   rÇ   r    r)   rÑ   r;   ÚpropertyrW   r^   rç   r   r&   r!   r   r   r   &  sR   „ ñòò"*òX%òNN6ð` ñ	%ó ð	%ð ñ'ó ð'ò($ó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Úangler-   s         r   r(   r(   O  sv   € ð Ðä�x‰x˜¤b§j¡jÔ1Ð1Ø	Ð	Ü" :Ó.‰Ø	Ð	˜eÐ/Ü  ¨Ó-‰ä—‘˜“ˆàÐð 	ˆr�ˆr�1ˆu‹˜Ñ$‹à€Mr!   )NNNNN)rª   r<   rT   r   Únumpyr?   ré   r   r   r   Útransformationsr   r	   r
   Útypedr   r   r   r   r   rø   r:   rF   r   r   r   r(   r&   r!   r   Ú<module>r      sp   ðÛ Û Ý ã ç Ý ß KÑ Kß DÕ Dð ˆB�F‰F�1‹I€	Ø$€	‡��Ñ ð Ð ÷Oñ O÷dfñ fðT	 FJôr!   