Ë
    :vžj1' ã                   ót  — U d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlmZmZmZmZmZmZmZmZ ddlmZ ddlmZ ddlmZmZ ddlmZ ddl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.m/Z/ erddl0Z1 ejd                  e3«      Z4ejj                  e6d<   ejn                  Z7ej                  Z8ejr                  Z9 e: e jv                  e jx                  «      jz                  dz  «      Z>e:e6d<   dZ?e:e6d<   dZ@eAe6d<    e j„                  de jx                  ¬«      ZCe jˆ                  e6d<   deCjŠ                  d<   e j                  j�                  «       ZGd¢de.de j                  j�                  fd„ZIdeJdeAfd„ZK	 	 d£de%deAde:dz  fd„ZLde%d e%de jx                  fd!„ZMd"e$de&fd#„ZNd"eOdeAfd$„ZPd"eOdeAfd%„ZQd"e$deAfd&„ZR	 d¤d"e*e$z  d'eeSeTeSd(f   z     d)eAdeAfd*„ZUd"e$deVfd+„ZW	 d¤de%d,eAfd-„ZXd.e%de,e jx                     fd/„ZYd0e%de,e jx                     fd1„ZZd2e)e$   fd3„Z[e j¸                  jº                  Z]de%d e%de jˆ                  eTeS   e j¼                  e$   f   fd4„Z_d5e,e$   de+e jx                     fd6„Z`	 d¤d7e%d8eAde,e jx                     eTe,e jx                     eAf   z  fd9„Zad:e%d;e-e%z  de,e jx                     fd<„Zbd:e%d=e(e%z  de,e jx                     fd>„Zcd?e%e)eTee$f      z  dejÈ                  eeVf   fd@„Zed5eOde$fdA„ZfdBe/deAfdC„ZgdBe/deSfdD„Zhd¢dEe'dFe(dz  deSfdG„ZiejÔ                  dddHdHddHfdIe(dJejÖ                  dz  dKeejj                     dz  dLeAdMeAdNe)eJ   dz  dOeAddfdP„ZldQe%de*fdR„ZmdSe)e%   dTe)e%   deTe,e jÜ                     e,e jÞ                     f   fdU„Zp	 	 	 	 d¥dVe%dWeJdXeJdYe(dZeJdeJfd[„Zq	 	 	 	 d¥dVe%dWeJdXeJdYe(dZeJdeJfd\„Zr	 	 d¦dVe%d]e j:                  jæ                  dz  d^eJdeeJe$f   fd_„Ztd§d`eue$e$f   d^eJdeueJe$f   fda„Zvd¨dbeJdceJddeJdeJfde„Zwdfe%eue$e$f   z  de*fdg„Zxd"eOdeJeVeJ   z  deAfdh„Zyd©d"eOdie(deVez   fdj„Z{d"eOdeJdezfdk„Z|d¢dªdl„Z}	 	 	 	 d«dme)e%   dneAdoeAdpe(dz  dqeAf
dr„Z~d¬d5e*d=e(dseAde*fdt„Zd"eOdue$deJfdv„Z€dw„ Z�d:e%de$fdx„Z‚dyeJeƒz  deez  fdz„Z„d­d{e%d|e%de+e jx                     fd}„Z…d{e%d|e%deTe+e �j                     e+e jx                     f   fd~„Z‡dZˆdBeƒe/z  d€eJdeueJe/dz  f   fd�„Z‰d‚eeJeJeƒz  e/z  f   due$deƒfdƒ„ZŠd¢d„eJd…e)eJ   dz  deJfd†„Z‹d‡e%ee%   z  de,e �j                     fdˆ„ZŒd‰e)e%   de,e �j                     fdŠ„Z�d‹e)e%   de*fdŒ„ZŽ	 d§dBe/d�eJeƒz  d^eJdeJeƒz  fdŽ„Z�d®d�e(deJfd�„Z�d¯d‘e%d’e:de,e jx                     fd“„Z‘	 d°de-e*z  d e-e*z  d”e'de �j$                  e*e �j$                     z  fd•„Z“d°de-e*z  d e-e*z  d”e'deAfd–„Z” G d—„ d˜eeJed(e$f   f   «      Z•d§dbeJeƒz  d™eJdeJfdš„Z–dbe$deJfd›„Z—d¤d7e%dœeAfd�„Z˜	 d¢džeJdz  dŸeeJ   d eeJdz  eSf   dz  deJfd¡„Z™y)±z 
Grab bag of utility functions.
é    N)ÚCallableÚ
CollectionÚHashableÚIteratorÚMappingÚMutableMappingÚ
MutableSetÚSequence)Údeepcopy)Úasdict)ÚBytesIOÚStringIO)ÚTYPE_CHECKINGé   )Úchain)ÚAnyÚ	ArrayLikeÚ
BoolIsFileÚFloatingÚIntegerÚIterableÚNDArrayÚ	NDArray1DÚ	NDArray2DÚNumberÚSeedÚStreamÚlogéd   ÚTOL_ZEROç:Œ0âŽyE>Ú	TOL_MERGEFÚ_STRICTé   ©ÚdtypeÚ	_IDENTITYÚ	WRITEABLEÚseedÚreturnc                 óP   — | €t         S t        j                  j                  | «      S )aÌ  
    Get a random generator, optionally seeded for deterministic results.

    Parameters
    ----------
    seed
      If None use a shared generator seeded from OS entropy. An integer
      seeds a fresh generator. A `Generator` is returned unaltered which
      lets a caller thread one stream through nested calls rather than
      re-seeding each of them to identical values.

    Returns
    -------
    generator
      Draw random values from this.
    )Ú_RANDOM_DEFAULTÚnpÚrandomÚdefault_rng)r)   s    ú]/workspace/moltex-experiments/.pixi/envs/default/lib/python3.12/site-packages/trimesh/util.pyÚrandom_generatorr1   S   s&   € ð" €|ô ÐÜ�9‰9× Ñ  Ó&Ð&ó    Únamec                 ó"   — ddl m}  || «      duS )a  
    Check to see if a module is installed by name without
    actually importing the module.

    Parameters
    ------------
    name : str
      The name of the module to check

    Returns
    ------------
    installed : bool
      True if module is installed
    r   )Ú	find_specN)Úimportlib.utilr5   )r3   r5   s     r0   Ú
has_moduler7   k   s   € õ )á�T‹? $Ð&Ð&r2   ÚvectorsÚcheck_validÚ	thresholdc                 ó  — t        j                  | «      } |€t        }t        | j                  «      dk(  rdt        j
                  t        j                  | | z  dg| j                  d   z  «      «      }||kD  }||xx   dz  cc<   | |j                  d«      z  }njt        | j                  «      dk(  rGt        j
                  t        j                  | | «      «      }||kD  }|r| |z  }n| j                  «       }nt        d«      ‚|r||   |fS |S )aæ  
    Unitize a vector or an array or row-vectors.

    Parameters
    ------------
    vectors : (n,m) or (j) float
       Vector or vectors to be unitized
    check_valid :  bool
       If set, will return mask of nonzero vectors
    threshold : float
       Cutoff for a value to be considered zero.

    Returns
    ---------
    unit :  (n,m) or (j) float
       Input vectors but unitized
    valid : (n,) bool or bool
        Mask of nonzero vectors returned if `check_valid`
    é   ç      ð?r   éÿÿÿÿ©r>   r   z vectors must be (n, ) or (n, d)!)
r-   Ú
asanyarrayr    ÚlenÚshapeÚsqrtÚdotÚreshapeÚcopyÚ
ValueError)r8   r9   r:   ÚnormÚvalidÚunits         r0   ÚunitizerK      sù   € ô2 �m‰m˜GÓ$€Gð ÐÜˆ	ä
ˆ7�=‰=Ó˜QÒô �w‰w”r—v‘v˜g¨Ñ/°#°¸¿¹ÀqÑ9IÑ1IÓJÓKˆà�yÑ ˆàˆU‹˜Ñ‹à˜Ÿ™ gÓ.Ñ.‰ä	ˆW�]‰]Ó	˜qÒ	 ä�w‰w”r—v‘v˜g wÓ/Ó0ˆØ�yÑ ˆÙØ˜T‘>‰Dà—<‘<“>‰DäÐ;Ó<Ð<áØ�E‰{˜EÐ!Ð!Ø€Kr2   ÚaÚbc                 ó   — t        j                  dt        d¬«       t        j                  | t        j
                  ¬«      } t        j                  |t        j
                  ¬«      }t        j                  | |z
  dz  j                  «       «      S )zB
    DEPRECATED: use `np.linalg.norm(a - b)` instead of this.
    zp`trimesh.util.euclidean` is deprecated and will be removed in January 2025. replace with `np.linalg.norm(a - b)`r<   ©ÚcategoryÚ
stacklevelr%   )ÚwarningsÚwarnÚDeprecationWarningr-   r@   Úfloat64rC   Úsum©rL   rM   s     r0   Ú	euclideanrX   º   sg   € ô ‡M�Mð	1ô $Øõô 	�‰�aœrŸz™zÔ*€AÜ
�‰�aœrŸz™zÔ*€AÜ�7‰7�Q˜‘U˜q‘L×%Ñ%Ó'Ó(Ð(r2   Úobjc                 ó6   — t        | d«      xs t        | d«      S )zÑ
    Check if an object is file-like

    Parameters
    ------------
    obj : object
       Any object type to be checked

    Returns
    -----------
    is_file : bool
        True if object is a file
    ÚreadÚwrite)Úhasattr©rY   s    r0   Úis_filer_   Ë   s   € ô �3˜ÓÒ8¤7¨3°Ó#8Ð8r2   c                 ól   — | j                   j                  }t        | d«      xr |j                  d«      S )zè
    Check if the object is a `pathlib.Path` or subclass.

    Parameters
    ------------
    obj : object
      Object to be checked

    Returns
    ------------
    is_pathlib : bool
      Is the input object a pathlib path
    ÚabsoluteÚPath)Ú	__class__Ú__name__r]   Úendswith©rY   r3   s     r0   Ú
is_pathlibrg   Ü   s.   € ð �=‰=×!Ñ!€DÜ�3˜
Ó#Ò=¨¯©°fÓ(=Ð=r2   c                 óZ   — t        j                  dt        d¬«       t        | t        «      S )zp
    DEPRECATED : this is not necessary since we dropped Python 2.

    Replace with `isinstance(obj, str)`
    zo`trimesh.util.is_string` is deprecated and will be removed in January 2025. replace with `isinstance(obj, str)`r<   rO   )rR   rS   rT   Ú
isinstanceÚstrr^   s    r0   Ú	is_stringrk   ï   s,   € ô ‡M�Mð	0ô $Øõô �cœ3ÓÐr2   c                 ó  ‡ — t        ‰ d«       xr t        ‰ d«      xs t        ‰ d«      }|xr# t        ˆ fd„t        t        t        fD «       «      }|xr t        ‰ «      j                  dv}t        ‰ d«      r|xr ‰ j                  dk7  }|S )zâ
    Check if an object is a sequence or not.

    Parameters
    -------------
    obj : object
      Any object type to be checked

    Returns
    -------------
    is_sequence : bool
        True if object is sequence
    ÚstripÚ__getitem__Ú__iter__c              3   ó8   •K  — | ]  }t        ‰|«       –— Œ y ­w©N)ri   ©Ú.0ÚirY   s     €r0   Ú	<genexpr>zis_sequence.<locals>.<genexpr>  s   øè ø€ ÐGÑ6F°œ* S¨!Ó,Ô,Ñ6Fùs   ƒ)Ú
PointCloudrB   © )r]   ÚallÚdictÚsetrj   Útyperd   rB   )rY   Úseqs   ` r0   Úis_sequencer}      sŽ   ø€ ô �s˜GÓ$Ð$ÒD¬°°mÓ)Dò ÌØˆZóJ€Cð
 Ò
G”#ÓG´t¼SÄ#Ñ6FÓGÓG€Cð Ò
:”$�s“)×$Ñ$¨NÐ:€Cô ˆs�GÔØÒ%�c—i‘i 2‘oˆà€Jr2   rB   .Úallow_zerosc                 ó:  — t        | d«      r!t        | j                  «      t        |«      k7  ryt        | «      dk(  rd|v ryt        | j                  |«      D ]A  \  }}t	        |t
        t        f«      r||v rŒ! yt        |«      dk  r
|dk(  r|s yŒ;||k7  sŒA y y)a[  
    Compare the shape of a numpy.ndarray to a target shape,
    with any value less than zero being considered a wildcard

    Note that if a list-like object is passed that is not a numpy
    array, this function will not convert it and will return False.

    Parameters
    ------------
    obj :   np.ndarray
      Array to check the shape on
    shape : list or tuple
      Any negative term will be considered a wildcard
      Any tuple term will be evaluated as an OR
    allow_zeros: bool
      if False, zeros do not match negatives in shape

    Returns
    ---------
    shape_ok : bool
      True if shape of obj matches query shape

    Examples
    ------------------------
    In [1]: a = np.random.random((100, 3))

    In [2]: a.shape
    Out[2]: (100, 3)

    In [3]: trimesh.util.is_shape(a, (-1, 3))
    Out[3]: True

    In [4]: trimesh.util.is_shape(a, (-1, 3, 5))
    Out[4]: False

    In [5]: trimesh.util.is_shape(a, (100, -1))
    Out[5]: True

    In [6]: trimesh.util.is_shape(a, (-1, (3, 4)))
    Out[6]: True

    In [7]: trimesh.util.is_shape(a, (-1, (4, 5)))
    Out[7]: False
    rB   Fr   r>   T)r]   rA   rB   Úzipri   ÚlistÚtupleÚint)rY   rB   r~   rt   Útargets        r0   Úis_shaper…      s¢   € ôj �3˜Ô ¤C¨¯	©	£N´c¸%³jÒ$@Øô ˆ3ƒx�1‚}˜˜u™Øô
 ˜Ÿ™ EÖ*‰	ˆˆ6ô �fœt¤U˜mÔ,Ø�F‰{àáô ˆv‹;˜Š?Ø�AŠv™kñ àð �Q‹;Ùð/ +ð6 r2   c                 ó4   — t        | «      rt        | «      S | gS )a™  
    Given an object, if it is a sequence return, otherwise
    add it to a length 1 sequence and return.

    Useful for wrapping functions which sometimes return single
    objects and other times return lists of objects.

    Parameters
    -------------
    obj : object
      An object to be made a sequence

    Returns
    --------------
    as_sequence : (n,) sequence
       Contains input value
    )r}   r�   r^   s    r0   Úmake_sequencer‡   }  s   € ô$ �3ÔÜ�C‹yÐàˆuˆr2   Úreturn_signc           
      ó¾  — t        j                  | t         j                  ¬«      } t        | d«      rœ| t         k  }t        j
                  t        j                  || t        kD  «      «      }t        j                  t        | «      t         j                  ¬«      }d||dd…df   <   d|t        j                  |dd…df   |dd…df   «      <   nõt        | d«      rÞ| t         k  }t        j
                  t        j                  || t        kD  «      «      }t        j                  t        | «      t         j                  ¬«      }d||dd…df   <   d|t        j                  |dd…df   |dd…df   «      <   d|t        j                  t        j                  |dd…df   |dd…df   «      |dd…df   «      <   nt        d	«      ‚| |j                  d
«      z  }|r||fS |S )a–  
    For a set of 3D vectors alter the sign so they are all in the
    upper hemisphere.

    If the vector lies on the plane all vectors with negative Y
    will be reversed.

    If the vector has a zero Z and Y value vectors with a
    negative X value will be reversed.

    Parameters
    ------------
    vectors : (n, 3) float
      Input vectors
    return_sign : bool
      Return the sign mask or not

    Returns
    ----------
    oriented: (n, 3) float
      Vectors with same magnitude as source
      but possibly reversed to ensure all vectors
      are in the same hemisphere.
    sign : (n,) float
      [OPTIONAL] sign of original vectors
    r%   ©r>   r<   g      ð¿Nr   r   ©r>   é   r<   zvectors must be (n, 3)!r?   )r-   r@   rU   r…   r    Úlogical_notÚ
logical_orÚonesrA   Úlogical_andrG   rE   )r8   rˆ   ÚnegativeÚzeroÚsignsÚorienteds         r0   Úvector_hemispherer•   •  sš  € ô> �m‰m˜G¬2¯:©:Ô6€Gä�˜Ô!ð œh˜YÑ&ˆÜ�~‰~œbŸm™m¨H°gÄÑ6HÓIÓJˆä—‘œ˜G›¬B¯J©JÔ7ˆà $ˆˆh’q˜!�t‰nÑð =AˆŒb�n‰n˜T¢! Q $™Z¨²!°Q°$©Ó8Ò9ä	�'˜7Ô	#àœh˜YÑ&ˆÜ�~‰~œbŸm™m¨H°gÄÑ6HÓIÓJˆô —‘œ˜G›¬B¯J©JÔ7ˆà $ˆˆh’q˜!�t‰nÑà<@ˆŒb�n‰n˜T¢! Q $™Z¨²!°Q°$©Ó8Ñ9ð
 ð 	Ü�N‰Nœ2Ÿ>™>¨$ªq°!¨t©*°dº1¸a¸4±jÓAÀ8ÊAÈqÈDÁ>ÓRò	
ô
 Ð2Ó3Ð3ð ˜Ÿ™ wÓ/Ñ/€HáØ˜ˆÐà€Or2   Ú	cartesianc                 óÞ  — t        j                  | t         j                  ¬«      } t        | d«      st	        d«      ‚t        | d¬«      \  }}d|t        j                  |«      t        k  <   |j                  \  }}}t        j                  t        | «      dft         j                  ¬«      }t        j                  t        j                  ||«      t        j                  |«      f«      ||<   |S )zû
    Convert a set of cartesian points to (n, 2) spherical unit
    vectors.

    Parameters
    ------------
    cartesian : (n, 3) float
       Points in space

    Returns
    ------------
    spherical : (n, 2) float
       Angles, in radians
    r%   r‹   z Cartesian points must be (n, 3)!T)r9   ç        r<   )r-   r@   rU   r…   rG   rK   Úabsr"   ÚTÚzerosrA   Úcolumn_stackÚarctan2Úarccos)r–   rJ   rI   ÚxÚyÚzÚ	sphericals          r0   Úvector_to_sphericalr£   â  s²   € ô —‘˜i¬r¯z©zÔ:€IÜ�I˜wÔ'ÜÐ;Ó<Ð<ä˜)°Ô6�K€Dˆ%Ø%(€DŒ�‰�‹œ	Ñ	!Ñ"à�f‰f�G€A€qˆ!Ü—‘œ#˜i›.¨!Ð,´B·J±JÔ?€IÜ—‘¬¯
©
°1°aÓ(8¼"¿)¹)ÀA»,Ð'GÓH€IˆeÑØÐr2   r¢   c                 ó|  — t        j                  | t         j                  ¬«      } t        | d«      st	        d«      ‚| j
                  \  }}t        j                  |«      t        j                  |«      }}t        j                  |«      t        j                  |«      }}t        j                  ||z  ||z  |f«      S )zõ
    Convert an array of `(n, 2)` spherical angles to `(n, 3)` unit vectors.

    Parameters
    ------------
    spherical : (n , 2) float
       Angles, in radians

    Returns
    -----------
    vectors : (n, 3) float
      Unit vectors
    r%   rŠ   z%spherical coordinates must be (n, 2)!)	r-   r@   rU   r…   rG   rš   ÚsinÚcosrœ   )r¢   ÚthetaÚphiÚstÚctÚspÚcps          r0   Úspherical_to_vectorr­   þ  s‹   € ô —‘˜i¬r¯z©zÔ:€IÜ�I˜wÔ'ÜÐ@ÓAÐAà—‘�J€Eˆ3Ü�V‰V�E‹]œBŸF™F 5›Mˆ€BÜ�V‰V�C‹[œ"Ÿ&™& ›+ˆ€BÜ�?‰?˜B ™G R¨"¡W¨bÐ1Ó2Ð2r2   Úiterablec                 ó.  — t        | t        j                  «      rM| j                  d«      } t        j                  | | f«      }|j                  d«      dd j                  d«      }|S ddl}|j                  | «      \  }}t        |«       t        ||«      S )a—  
    For an iterable, group values into pairs.

    Parameters
    ------------
    iterable : (m, ) list
       A sequence of values

    Returns
    -----------
    pairs: (n, 2)
      Pairs of sequential values

    Example
    -----------
    In [1]: data
    Out[1]: [0, 1, 2, 3, 4, 5, 6]

    In [2]: list(trimesh.util.pairwise(data))
    Out[2]: [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

    r>   r   rŠ   r   N)	ri   r-   ÚndarrayrE   rœ   Ú	itertoolsÚteeÚnextr€   )r®   ÚstackedÚpairsr±   rL   rM   s         r0   Úpairwiser¶     s„   € ô2 �(œBŸJ™JÔ'Ø×#Ñ# BÓ'ˆÜ—/‘/ 8¨XÐ"6Ó7ˆØ—‘ Ó# A bÐ)×1Ñ1°'Ó:ˆØˆó à�=‰=˜Ó"�D€A€qäˆ„Gäˆq�!‹9Ðr2   c                 ó€   — t        j                  | «      } t        j                  | |z  dg| j                  d   z  «      S )aD  
    Dot product by row of a and b.

    There are a lot of ways to do this though
    performance varies very widely. This method
    uses a dot product to sum the row and avoids
    function calls if at all possible.

    Comparing performance of some equivalent versions:
    ```
    In [1]: import numpy as np; import trimesh

    In [2]: a = np.random.random((10000, 3))

    In [3]: b = np.random.random((10000, 3))

    In [4]: %timeit (a * b).sum(axis=1)
    1000 loops, best of 3: 181 us per loop

    In [5]: %timeit np.einsum('ij,ij->i', a, b)
    10000 loops, best of 3: 62.7 us per loop

    In [6]: %timeit np.diag(np.dot(a, b.T))
    1 loop, best of 3: 429 ms per loop

    In [7]: %timeit np.dot(a * b, np.ones(a.shape[1]))
    10000 loops, best of 3: 61.3 us per loop

    In [8]: %timeit trimesh.util.diagonal_dot(a, b)
    10000 loops, best of 3: 55.2 us per loop
    ```

    Parameters
    ------------
    a : (m, d) float
      First array
    b : (m, d) float
      Second array

    Returns
    -------------
    result : (m,) float
      Dot product of each row
    r=   r   )r-   r@   rD   rB   rW   s     r0   Údiagonal_dotr¸   B  s9   € ô` 	�‰�aÓ€Aô �6‰6�!�a‘%˜#˜ §¡¨¡Ñ+Ó,Ð,r2   Údatac                 ó|   — t        j                  t        j                  | dz  dg| j                  d   z  «      «      S )a  
    Compute the norm per-row of a numpy array.

    This is identical to np.linalg.norm(data, axis=1) but roughly
    three times faster due to being less general.

    In [3]: %timeit trimesh.util.row_norm(a)
    76.3 us +/- 651 ns per loop

    In [4]: %timeit np.linalg.norm(a, axis=1)
    220 us +/- 5.41 us per loop

    Parameters
    -------------
    data : (n, d) float
      Input 2D data to calculate per-row norm of

    Returns
    -------------
    norm : (n,) float
      Norm of each row of input array
    r<   r   )r-   rC   rD   rB   )r¹   s    r0   Úrow_normr»   x  s1   € ô. �7‰7”2—6‘6˜$ ™' A 3¨¯©°A©Ñ#6Ó7Ó8Ð8r2   ÚpointsÚ	return_2Dc                 ó^  — t        j                  | t         j                  ¬«      } | j                  }|dk(  rd}nmt	        |«      dk7  rt        d«      ‚|d   dk(  r6t        j                  | t        j                  t	        | «      «      f«      } d}n|d   dk(  rd}nt        d	«      ‚|r| |fS | S )
až  
    For a list of (n, 2) or (n, 3) points return them
    as (n, 3) 3D points, 2D points on the XY plane.

    Parameters
    ------------
    points :  (n, 2) or (n, 3) float
      Points in either 2D or 3D space
    return_2D : bool
      Were the original points 2D?

    Returns
    ----------
    points : (n, 3) float
      Points in space
    is_2D : bool
      [OPTIONAL] if source points were (n, 2)
    r%   )r   Fr<   zPoints must be 2D array!r   TrŒ   z Points must be (n, 2) or (n, 3)!)r-   r@   rU   rB   rA   rG   rœ   r›   )r¼   r½   rB   Úis_2Ds       r0   Ústack_3DrÀ   ’  s¢   € ô, �]‰]˜6¬¯©Ô4€FØ�L‰L€Eà�‚}Ø‰Ü	ˆU‹�qŠÜÐ3Ó4Ð4Ø	ˆq‰�QŠÜ—‘ &¬"¯(©(´3°v³;Ó*?Ð!@ÓAˆØ‰Ø	ˆq‰�QŠØ‰äÐ;Ó<Ð<áØ�uˆ}Ðà€Mr2   ÚboundsÚstepc           	      óP  — t        j                  | t         j                  ¬«      } t        | «      dk7  rt	        d«      ‚t        j                  |t         j                  ¬«      }|j
                  dk(  r#t        j                  || j
                  d   «      }t        | j                  |«      D ��cg c]  \  }}t        j                  |d|iŽ‘Œ }}}t        j                  t        j                  |ddiŽ«      j                  | j
                  d   d	«      j                  }|S c c}}w )
a`  
    Return a grid from an (2,dimension) bounds with samples step distance apart.

    Parameters
    ------------
    bounds: (2,dimension) list of [[min x, min y, etc], [max x, max y, etc]]
    step:   float, or (dimension) floats, separation between points

    Returns
    ---------
    grid: (n, dimension), points inside the specified bounds
    r%   r<   úbounds must be (2, dimension!rw   r   rÂ   ÚindexingÚijr>   )r-   r@   rU   rA   rG   rB   Útiler€   rš   ÚarangeÚvstackÚmeshgridrE   )rÁ   rÂ   rM   ÚsÚgrid_elementsÚgrids         r0   Úgrid_arangerÎ   ½  sâ   € ô �]‰]˜6¬¯©Ô4€FÜ
ˆ6ƒ{�aÒÜÐ8Ó9Ð9ô �=‰=˜¤R§Z¡ZÔ0€DØ‡z�z�RÒÜ�w‰w�t˜VŸ\™\¨!™_Ó-ˆä7:¸6¿8¹8ÀTÔ7JÔKÑ7J©t¨q°!”R—Y‘Y Ð*¨Ó*Ð7J€MÑKä
�	‰	”"—+‘+˜}Ð<°tÑ<Ó=ß	‰�—‘˜a‘ "Ó	%ß	
‰ð 	ð
 €Kùó Ló   Â/D"Úcountc           	      óP  — t        j                  | t         j                  ¬«      } t        | «      dk7  rt	        d«      ‚t        j                  |t         j
                  ¬«      }|j                  dk(  r#t        j                  || j                  d   «      }t        | j                  |«      D ��cg c]  \  }}t        j                  |d|iŽ‘Œ }}}t        j                  t        j                  |ddiŽ«      j                  | j                  d   d	«      j                  }|S c c}}w )
ab  
    Return a grid spaced inside a bounding box with edges spaced using np.linspace.

    Parameters
    ------------
    bounds: (2,dimension) list of [[min x, min y, etc], [max x, max y, etc]]
    count:  int, or (dimension,) int, number of samples per side

    Returns
    ---------
    grid: (n, dimension) float, points in the specified bounds
    r%   r<   rÄ   rw   r   ÚnumrÅ   rÆ   r>   )r-   r@   rU   rA   rG   Úint64rB   rÇ   r€   rš   ÚlinspacerÉ   rÊ   rE   )rÁ   rÐ   rM   ÚcrÌ   rÍ   s         r0   Úgrid_linspacerÖ   Ü  sà   € ô �]‰]˜6¬¯©Ô4€FÜ
ˆ6ƒ{�aÒÜÐ8Ó9Ð9ä�M‰M˜%¤r§x¡xÔ0€EØ‡{�{�bÒÜ—‘˜˜vŸ|™|¨A™Ó/ˆä8;¸F¿H¹HÀeÔ8LÔMÑ8L±°°1”R—[‘[ !Ð+¨Ó+Ð8L€MÑMä
�	‰	”"—+‘+˜}Ð<°tÑ<Ó=ß	‰�—‘˜a‘ "Ó	%ß	
‰ð 	ð
 €Kùó NrÏ   rµ   c                 ót   — t        j                  t        «      }| D ]  \  }}||   j                  |«       Œ |S )av  
    Given a set of key value pairs, create a dictionary.
    If a key occurs multiple times, stack the values into an array.

    Can be called like the regular dict(pairs) constructor

    Parameters
    ------------
    pairs: (n, 2) array of key, value pairs

    Returns
    ----------
    result: dict, with all values stored (rather than last with regular dict)

    )ÚcollectionsÚdefaultdictr�   Úappend)rµ   ÚresultÚkÚvs       r0   Ú
multi_dictrÞ   ú  s9   € ô$ ×$Ñ$¤TÓ*€FÛ‰ˆˆ1Øˆq‰	×Ñ˜Õð à€Mr2   c                 óB   — t        j                  t        | «      «      }|S )a(  
    Ensure that any arrays or dicts passed containing
    numpy arrays are properly converted to lists

    Parameters
    -------------
    data : any
      Usually a dict with some numpy arrays as values

    Returns
    ----------
    result : any
      JSON-serializable version of data
    )ÚjsonÚloadsÚjsonify)r¹   rÛ   s     r0   Útolistrã     s   € ô �Z‰Zœ ›Ó&€FØ€Mr2   Úfile_objc                 óÄ   — | j                  «       }| j                  d«      }| j                  |«       t        |t        «      }|D ]  }|rt        |«      }n|}|dkD  sŒ y y)zH
    Returns True if file has non-ASCII characters (> 0x7F, or 127)
    i   é   TF)Útellr[   Úseekri   rj   Úord)rä   ÚstartÚfbytesÚis_strÚfbyteÚcodes         r0   Úis_binary_filerï   %  s_   € ð �M‰M‹O€EØ�]‰]˜4Ó €FØ‡M�M�%ÔÜ˜¤Ó$€FÛˆÙÜ�u“:‰DàˆDØ�#‹:Ùð ð r2   c                 ó–   — | j                  «       }| j                  dd«       | j                  «       }| j                  |«       ||z
  }|S )zÃ
    For an open file object how far is it to the end

    Parameters
    ------------
    file_obj: open file-like object

    Returns
    ----------
    distance: int, bytes to end of file
    r   r<   )rç   rè   )rä   Úposition_currentÚposition_endÚdistances       r0   Údistance_to_endrô   7  sF   € ð  —}‘}“ÐØ‡M�M�!�QÔØ—=‘=“?€LØ‡M�MÐ"Ô#ØÐ.Ñ.€HØ€Or2   ÚdecimalÚ
min_digitsc                 ó˜   — t        t        t        j                  | «      «      «      }|�t        j                  ||d«      }t        |«      S )a  
    Return the number of digits to the first nonzero decimal.

    Parameters
    -----------
    decimal:    float
    min_digits: int, minimum number of digits to return

    Returns
    -----------

    digits: int, number of digits to the first nonzero decimal
    é   )r™   rƒ   r-   Úlog10Úclip)rõ   rö   Údigitss      r0   Údecimal_to_digitsrü   K  s>   € ô ””R—X‘X˜gÓ&Ó'Ó(€FØÐÜ—‘˜ ¨RÓ0ˆÜˆv‹;Ðr2   TÚlevelÚhandlerÚloggersÚcolorsÚcapture_warningsÚ	blacklistÚonly_parentc                 ó(  ‡— |€g d¢}t        j                  |«       t        j                  dd«      }|r	 ddlm}  |dddd	d
ddddœ¬«      }|€t        j                  «       }|j                  |«       |j                  t        | «      «       |€;t        t         j                  j                  j                  j                  «       «      }|j                  t        j                   d«      «       dt        j                   d«      _        |D �	ci c]C  }	t%        |	d«      r5t'        |	t         j                  «      r|	j(                  |vr|	j(                  |	“ŒE }
}	|rMi }t+        |
j-                  «       «      D ]-  Št/        ˆfd„|j-                  «       D «       «      rŒ&|
‰   |‰<   Œ/ |}
|
j                  «       D ]-  }|j1                  |«       |j                  t        | «      «       Œ/ t3        j4                  dd¬«       y# t
        $ r Y �Œ½w xY wc c}	w )aD  
    Attach a stream handler to all loggers.

    Parameters
    ------------
    level : enum
      Logging level, like logging.INFO
    handler : None or logging.Handler
      Handler to attach
    loggers : None or (n,) logging.Logger
      If None, will try to attach to all available
    colors : bool
      If True try to use colorlog formatter
    blacklist : (n,) str
      Names of loggers NOT to attach to
    only_parent
      Only attach to parent loggers, i.e. `trimesh`, `trimesh.sub1`, `trimesh.sub2`
      will only attach to `trimesh` and not the sub-loggers
    N)
ÚTerminalIPythonAppÚ
PYREADLINEÚpyembreeÚshapelyÚ
matplotlibzparso.cacheÚparsozparso.python.diffÚasynciozprompt_toolkit.bufferzD[%(asctime)s] %(levelname)-7s (%(filename)s:%(lineno)3s) %(message)sz%Y-%m-%d %H:%M:%Sr   )ÚColoredFormatterzW%(log_color)s%(levelname)-8s%(reset)s %(filename)17s:%(lineno)-4s  %(blue)4s%(message)sTÚcyanÚgreenÚyellowÚred)ÚDEBUGÚINFOÚWARNINGÚERRORÚCRITICAL)ÚdatefmtÚresetÚ
log_colorszpy.warningsr  r3   c              3   óF   •K  — | ]  }‰j                  |› d �«      –— Œ y­w)Ú.N)Ú
startswith)rs   Úpr3   s     €r0   ru   z attach_to_log.<locals>.<genexpr>Ì  s#   øè ø€ ÐOÑ9N°A�t—‘¨!¨¨A w×/Ñ9Nùs   ƒ!é   )Ú	precisionÚsuppress)ÚloggingÚcaptureWarningsÚ	FormatterÚcolorlogr  ÚImportErrorÚStreamHandlerÚsetFormatterÚsetLevelrƒ   rz   ÚLoggerÚmanagerÚ
loggerDictÚvaluesÚaddÚ	getLoggerÚdisabledr]   ri   r3   ÚsortedÚkeysÚanyÚ
addHandlerr-   Úset_printoptions)rý   rþ   rÿ   r   r  r  r  Ú	formatterr  ÚLÚloggers_dictÚparent_loggersÚloggerr3   s                @r0   Úattach_to_logr9  _  sþ  ø€ ð< Ðò
ˆ	ô ×ÑÐ,Ô-ô ×!Ñ!ØNØó€Iñ ð	Ý1á(ðJð Øà#Ø#Ø'Ø"Ø %ñôˆIð& €Ü×'Ñ'Ó)ˆð ×Ñ˜Ô#à×Ñ”S˜“ZÔ ð €ä”g—n‘n×,Ñ,×7Ñ7×>Ñ>Ó@ÓAˆð ‡K�K”×!Ñ! -Ó0Ô1ð .2„G×Ñ�jÓ!Ô*ñ
 óáˆAÜ�1�fÔÜ�qœ'Ÿ.™.Ô)Ø�F‰F˜)Ñ#ð	 	
�‰�‰	Øð ð ñ àˆä˜<×,Ñ,Ó.Ö/ˆDäÓO¸×9LÑ9LÔ9NÓOÕOØ'3°DÑ'9�˜tÒ$ð 0ð
 &ˆð ×%Ñ%Ö'ˆØ×Ñ˜'Ô"Ø�‰œ˜E›
Õ#ð (ô
 ×Ñ !¨dÖ3øôc ò 	Úð	üò0s   ¶G? ÄAHÇ?	HÈHÚindicesc                 ó  — t        j                  | «      } t        | «      dk(  rt        j                  g «      S t	        | d   «      rdt        | d   «      f}nd}t        j
                  | dd | dd f«      j                  |«      S )aú  
    Stack a list of values that represent a polyline into
    individual line segments with duplicated consecutive values.

    Parameters
    ------------
    indices : (m,) any
      List of items to be stacked

    Returns
    ---------
    stacked : (n, 2) any
      Stacked items

    Examples
    ----------
    In [1]: trimesh.util.stack_lines([0, 1, 2])
    Out[1]:
    array([[0, 1],
           [1, 2]])

    In [2]: trimesh.util.stack_lines([0, 1, 2, 4, 5])
    Out[2]:
    array([[0, 1],
           [1, 2],
           [2, 4],
           [4, 5]])

    In [3]: trimesh.util.stack_lines([[0, 0], [1, 1], [2, 2], [3, 3]])
    Out[3]:
    array([[0, 0],
           [1, 1],
           [1, 1],
           [2, 2],
           [2, 2],
           [3, 3]])

    r   r>   rŠ   Nr   )r-   r@   rA   Úarrayr}   rœ   rE   )r:  rB   s     r0   Ústack_linesr=  Ú  s{   € ôN �m‰m˜GÓ$€GÜ
ˆ7ƒ|�qÒÜ�x‰x˜‹|ÐÜ	�W˜Q‘ZÔ	 Ø”S˜ ™“_Ð%‰àˆÜ�?‰?˜G C R˜L¨'°!°"¨+Ð6Ó7×?Ñ?ÀÓFÐFr2   Úvertices_seqÚ	faces_seqc                 ó8  — t        j                  | D �cg c]  }t        |«      ‘Œ c}t         j                  ¬«      }t        j                  dt        j
                  |«      dd «      }g }t        ||«      D ](  \  }}t        |«      dk(  rŒ|j	                  ||z   «       Œ* t        | «      }t        |«      }t        |«      dk(  r|j                  d«      }t        |«      dk(  r.|j                  d«      j                  t         j                  «      }||fS c c}w )að  
    Given a sequence of zero-indexed faces and vertices
    combine them into a single array of faces and
    a single array of vertices.

    Parameters
    -----------
    vertices_seq : (n, ) sequence of (m, d) float
      Multiple arrays of verticesvertex arrays
    faces_seq : (n, ) sequence of (p, j) int
      Zero indexed faces for matching vertices

    Returns
    ----------
    vertices : (i, d) float
      Points in space
    faces : (j, 3) int
      Reference vertex indices
    r%   r   Nr>   )r   rŒ   )
r-   r<  rA   rÓ   rÚ   Úcumsumr€   Úvstack_emptyrE   Úastype)	r>  r?  rt   Úvertices_lenÚface_offsetÚ	new_facesÚoffsetÚfacesÚverticess	            r0   Úappend_facesrJ    sð   € ô0 —8‘8©\Ó:©\¨œS �V¨\Ñ:Ä"Ç(Á(ÔK€Lä—)‘)˜AœrŸy™y¨Ó6°s¸Ð;Ó<€Kà€IÜ˜[¨)Ö4‰ˆ�Üˆu‹:˜Š?Øà×Ñ˜ ™Õ(ð	 5ô ˜LÓ)€Hä˜Ó#€Eô ˆ8ƒ}˜ÒØ×#Ñ# FÓ+ˆÜ
ˆ5ƒz�Q‚Ø—‘˜fÓ%×,Ñ,¬R¯X©XÓ6ˆà�Uˆ?Ðùò- ;s   ”Dr<  Ú	col_delimÚ	row_delimrû   Úvalue_formatc                 ó¤  — t        j                  | «      } t        |«      }t        |«      }t        |«      }t        |«      }t	        | j
                  «      dkD  rt        dt        | j
                  «      «      ‚| j                  j                  �t        d«      ‚|j                  d«      }| j                  j                  dv r||z   }n^| j                  j                  dk(  r%|j                  dd	t        |«      z   d
z   «      |z   }n t        d| j                  j                  «      ‚t	        |«      }t	        | j
                  «      dk(  r/|| j
                  d   z  }|dt	        |«        |z   }t	        |«      }|t	        | «      z  }t        j                  | j                  d«      d|f«      j                  d«      } |j                  |Ž d|  }	|	S )aJ  
    Convert a 1 or 2D array into a string with a specified number
    of digits and delimiter. The reason this exists is that the
    basic numpy array to string conversions are surprisingly slow.

    Parameters
    ------------
    array : (n,) or (n, d) float or int
       Data to be converted
       If shape is (n,) only column delimiter will be used
    col_delim : str
      What string should separate values in a column
    row_delim : str
      What string should separate values in a row
    digits : int
      How many digits should floating point numbers include
    value_format : str
       Format string for each value or sequence of values
       If multiple values per value_format it must divide
       into array evenly.

    Returns
    ----------
    formatted : str
       String representation of original array
    r<   ú-conversion only works on 1D/2D arrays not %s!Nz<array is  structured, use structured_array_to_string insteadÚ{©rt   ÚuÚfú{}ú{:.úf}údtype %s not convertible!r   r?   r>   )r-   r@   rƒ   rj   rA   rB   rG   r&   ÚnamesrÐ   ÚkindÚreplacer3   rÇ   rE   Úformat)
r<  rK  rL  rû   rM  ÚrepeatsÚ
format_strÚend_junkÚshapedÚ	formatteds
             r0   Úarray_to_stringra  <  s­  € ôD �M‰M˜%Ó €EÜ�‹[€FÜ�I“€IÜ�I“€IÜ�|Ó$€Lô ˆ5�;‰;Ó˜!ÒÜØ;¼SÀÇÁÓ=Mó
ð 	
ð
 ‡{�{×ÑÐ$ÜÐWÓXÐXð × Ñ  Ó%€Gà‡{�{×Ñ˜:Ñ%à! IÑ-‰
Ø	�‰×	Ñ	˜SÒ	 à!×)Ñ)¨$°¼¸F»Ñ0CÀdÑ0JÓKÈiÑW‰
äÐ4°e·k±k×6FÑ6FÓGÐGô �9‹~€Hä
ˆ5�;‰;Ó˜1ÒØ�e—k‘k !‘nÑ$ˆ
àÐ 1¤3 y£> /Ð2°YÑ>ˆ
Ü�y“>ˆð ”#�e“*Ñ€Jô �W‰W�U—]‘] 7Ó+¨a°¨\Ó:×BÑBÀ2ÓF€Fð "�
×!Ñ! 6Ð*¨:¨X¨IÐ6€IàÐr2   c           	      óR  — t        j                  | «      } t        |«      }t        |«      }t        |«      }t        |«      }t	        | j
                  «      dkD  rt        dt        | j
                  «      «      ‚| j                  j                  €t        d«      ‚|j                  d«      dkD  rt        d|«      ‚d}| j                  j                  D ]¬  }| |   j                  j                  }t	        | |   j
                  «      dk(  r| |   j
                  d   nd}|d	v r|j                  d
d«      |z   }	n@|dk(  r%|j                  d
dt        |«      z   dz   «      |z   }	nt        d| j                  «      ‚|||	z  z  }Œ® |dt	        |«        |z   }|t	        | «      z  }t	        | «      }
t        j                  | j                  j                  D �cg c]  }| |   j                  |
df«      ‘Œ c}«      j                  d«      } |j                  |Ž dt	        |«        }|S c c}w )aS  
    Convert an unstructured array into a string with a specified
    number of digits and delimiter. The reason thisexists is
    that the basic numpy array to string conversions are
    surprisingly slow.

    Parameters
    ------------
    array : (n,) or (n, d) float or int
       Data to be converted
       If shape is (n,) only column delimiter will be used
    col_delim : str
      What string should separate values in a column
    row_delim : str
      What string should separate values in a row
    digits : int
      How many digits should floating point numbers include
    value_format : str
       Format string for each value or sequence of values
       If multiple values per value_format it must divide
       into array evenly.

    Returns
    ----------
    formatted : str
       String representation of original array
    r   rO  Nz4array is not structured, use array_to_string insteadrP  zNvalue_format %s is invalid, repeating unstructured array values is unsupportedÚ r<   rQ  rT  z{:0.0f}rS  rU  rV  rW  r>   )r-   r@   rƒ   rj   rA   rB   rG   r&   rX  rÐ   rY  rZ  ÚhstackrE   r[  )r<  rK  rL  rû   rM  r]  r3   rY  Úelement_row_lengthÚelement_format_strrÐ   rÜ   Ú	flattenedr`  s                 r0   Ústructured_array_to_stringrh  �  s.  € ôF �M‰M˜%Ó €EÜ�‹[€FÜ�I“€IÜ�I“€IÜ�|Ó$€Lô ˆ5�;‰;Ó˜!ÒÜØ;¼SÀÇÁÓ=Mó
ð 	
ð
 ‡{�{×ÑÐ ÜÐOÓPÐPð ×Ñ˜#Ó Ò"Üð&àó
ð 	
ð €JØ—‘×!Ô!ˆØ�T‰{× Ñ ×%Ñ%ˆÜ58¸¸t¹×9JÑ9JÓ5KÈqÒ5P˜U 4™[×.Ñ.¨qÒ1ÐVWÐØ�:Ñà!-×!5Ñ!5°d¸IÓ!FÈÑ!RÑØ�SŠ[ð ×$Ñ$ T¨5´3°v³;Ñ+>ÀÑ+EÓFÈÑRñ ô Ð8¸%¿+¹+ÓFÐFØÐ(Ð+=Ñ=Ñ=‰
ð "ð  Ð-œs 9›~˜oÐ.°Ñ:€Jà”#�e“*Ñ€Jô �‹J€Eä—	‘	Ø05·±×0AÒ0AÓBÑ0A¨1ˆˆq‰×	Ñ	˜5 "˜+Õ	&Ð0AÑBóç�gˆbƒkð ð
 "�
×!Ñ! 9Ð-Ð.?´°Y³°Ð@€IàÐùò 	Cs   ÇH$r&   Úencodingc                 óØ  — t        j                  | «      } | j                  }t        j                  | «      }|€| j                  }t        j                  |«      j
                  |dœ}|dv rVt        j                  |j                  |«      j                  «       «      }t        |d«      r|j                  d«      }||d<   |S |dk(  r| j                  d¬«      |d<   |S t        d	|› d
�«      ‚)až  
    Export a numpy array to a compact serializable dictionary.

    Parameters
    ------------
    array : array
      Any numpy array
    dtype : str or None
      Optional dtype to encode array
    encoding : str
      'base64' or 'binary'

    Returns
    ---------
    encoded : dict
      Has keys:
      'dtype':  str, of dtype
      'shape':  tuple of shape
      'base64': str, base64 encoded string
    )r&   rB   )Úbase64Údict64Údecodeúutf-8rk  ÚbinaryÚC)Úorderz	encoding z is not available!)r-   r@   rB   Úravelr&   rj   rk  Ú	b64encoderC  Útobytesr]   rm  rG   )r<  r&   ri  rB   ÚflatÚencodedÚpackeds          r0   Úarray_to_encodedrx  í  sß   € ô2 �M‰M˜%Ó €EØ�K‰K€Eä�8‰8�E‹?€DØ€}Ø—‘ˆä(*¯©°«×(;Ñ(;ÀeÑL€GØÐ'Ñ'Ü×!Ñ! $§+¡+¨eÓ"4×"<Ñ"<Ó">Ó?ˆÜ�6˜8Ô$Ø—]‘] 7Ó+ˆFØ"ˆ�Ñð
 €Nð	 
�XÒ	Ø!ŸM™M°˜MÓ4ˆ�Ñð €Nô ˜9 X JÐ.@ÐAÓBÐBr2   Ústorec                 óÌ   — | j                  «       }|D ]N  }t        |d«      sŒ|j                  |«      }||k7  sŒ'| |   | |j                  |«      <   | j                  |«       ŒP | S )aÂ  
    If a dictionary has keys that are bytes decode them to a str.

    Parameters
    ------------
    store : dict
      Dictionary with data

    Returns
    ---------
    result : dict
      Values are untouched but keys that were bytes
      are converted to ASCII strings.

    Example
    -----------
    In [1]: d
    Out[1]: {1020: 'nah', b'hi': 'stuff'}

    In [2]: trimesh.util.decode_keys(d)
    Out[2]: {1020: 'nah', 'hi': 'stuff'}
    rm  )r0  r]   rm  Úpop)ry  ri  r0  ÚkeyÚdecodeds        r0   Údecode_keysr~    sa   € ð. �:‰:‹<€DÛˆÜ�3˜Õ!Ø—j‘j Ó*ˆGØ�g‹~Ø.3°C©j��c—j‘j Ó*Ñ+Ø—	‘	˜#•ð ð €Lr2   ÚtextÚstarts_withÚnew_linec                 ó  — || vr| S | |z   j                  |«      }| j                  |«      rd}n|d   }|D �cg c]  }|j                  |d«      ‘Œ }}||z   |j                  d„ |D «       «      z   }|j                  «       }|S c c}w )a\  
    Strip comments from a text block.

    Parameters
    -----------
    text : str
      Text to remove comments from
    starts_with : str
      Character or substring that starts a comment
    new_line : str
      Character or substring that ends a comment

    Returns
    -----------
    stripped : str
      Text with comments stripped
    rc  r   r   c              3   óh   K  — | ]*  }t        |«      d kD  sŒt        |d    «      dkD  sŒ$|d    –— Œ, y­w)r   r   N)rA   )rs   rt   s     r0   ru   z comment_strip.<locals>.<genexpr>a  s-   è ø€ ÐN¡g ´°Q³¸!³ÄÀAÀaÁDÃ	ÈAÃ˜˜!�¡gùs   ‚2–2¨
2)Úsplitr  Újoinrm   )r  r€  r�  r„  Úleadrt   ÚremovedrÛ   s           r0   Úcomment_striprˆ  <  s¥   € ð& ˜$ÑØˆð �H‰_×#Ñ# KÓ0€Eð ‡��{Ô#Ø‰à�Q‰xˆñ .3Ó3©U¨ˆq�w‰w�x Õ#¨U€GÐ3ð 	Ø
ñ	à
�-‰-ÑN¡gÓNÓ
Nñ	Oð ð �\‰\‹^€Fà€Mùò 4s   ¸Brv  c                 ó¬  — t        | t        «      s-t        | «      rt        j                  | «      }|S t        d«      ‚t        | «      }t        j                  |d   «      }d|v r-t        j                  t        j                  |d   «      |«      }n*d|v rt        j                  |d   |¬«      }nt        d«      ‚d|v r|j                  |d   «      }|S )aa  
    Turn a dictionary with base64 encoded strings back into a numpy array.

    Parameters
    ------------
    encoded
      Has keys:
        dtype: string of dtype
        shape: int tuple of shape
        base64: base64 encoded string of flat array
        binary:  decode result coming from numpy.tobytes

    Returns
    ----------
    array
    z(Unable to extract numpy array from inputr&   rk  ro  r%   z8Invalid encoded array, no 'base64' or 'binary' key foundrB   )ri   ry   r}   r-   r@   rG   r~  r&   Ú
frombufferrk  Ú	b64decoderE   )rv  Úas_arrayÚencoded_dictr&   r<  s        r0   Úencoded_to_arrayrŽ  i  sÃ   € ô$ �gœtÔ$Ü�wÔÜ—}‘} WÓ-ˆHØˆOäÐGÓHÐHä˜wÓ'€Lä�H‰H�\ 'Ñ*Ó+€EØ�<ÑÜ—‘œf×.Ñ.¨|¸HÑ/EÓFÈÓN‰Ø	�\Ñ	!Ü—‘˜l¨8Ñ4¸EÔB‰äÐSÓTÐTØ�,ÑØ—‘˜l¨7Ñ3Ó4ˆØ€Lr2   c                 ó†   ‡ — 	 t        |t        «      rt        ˆ fd„|D «       «      S t        ‰ |«       y# t        $ r Y yw xY w)ah  
    Given an object, if it is a member of the class 'name',
    or a subclass of 'name', return True.

    Parameters
    ------------
    obj : instance
      Some object of some class
    name: str
      The name of the class we want to check for

    Returns
    ---------
    is_instance : bool
      Whether the object is a member of the named class
    c              3   ó6   •K  — | ]  }t        ‰|«      –— Œ y ­wrq   )Úis_instance_namedrr   s     €r0   ru   z$is_instance_named.<locals>.<genexpr>£  s   øè ø€ Ð?¹$°QÔ(¨¨a×0¹$ùs   ƒTF)ri   r�   r1  Ú
type_namedrG   rf   s   ` r0   r‘  r‘  �  sB   ø€ ð"Ü�dœDÔ!ÜÓ?¹$Ó?Ó?Ð?ä�s˜DÔ!ØøÜò Ùðús   ƒ#4 §4 ´	A ¿A Údepthc                 ó‚  — t        j                  t        | j                  j                  «      g«      }t        |«      D ]1  }|j                  |d   D �cg c]  }|€Œ|j                  ‘Œ c}«       Œ3 	 t        j                  |«      }|D �cg c]  }t        |d«      sŒ|‘Œ c}S c c}w # t        $ r g cY S w xY wc c}w )z0
    Return the bases of the object passed.
    r>   rd   )rØ   Údequer�   rc   Ú	__bases__ÚrangerÚ   Ú__base__r-   rd  Ú
IndexErrorr]   )rY   r“  Úbasesrt   Ú
bases_flats        r0   Ú
type_basesrœ  «  s¬   € ô &1×%6Ñ%6¼¸S¿]¹]×=TÑ=TÓ8UÐ7VÓ%W€EÜ�5Ž\ˆØ�‰¨%°ª)ÓE©) Q°q±}�a—j“j¨)ÑEÕFð ðÜ—Y‘Y˜uÓ%ˆ
ñ "Ó<‘z�!¤W¨Q°
Õ%;ŠA�zÑ<Ð<ùò Føô ò ØŠ	ðüâ<s*   ÁB&
ÁB&
Á4B+ ÂB<ÂB<Â+B9Â8B9c                 óÄ   — t        |«      }| j                  j                  |k(  r| j                  S t        | «      D ]  }|j                  |k(  sŒ|c S  t	        d|z   «      ‚)a,  
    Similar to the type() builtin, but looks in class bases
    for named instance.

    Parameters
    ------------
    obj : any
      Object to look for class of
    name : str
      Name of class

    Returns
    ----------
    class : type
      Named class, raises ValueError if not found
    z Unable to extract class of name )rj   rc   rd   rœ  rG   )rY   r3   Úbases      r0   r’  r’  ¹  s[   € ô$ ˆt‹9€DØ
‡}�}×Ñ Ò%Ø�}‰}ÐÜ˜3–ˆØ�=‰=˜DÓ ØŠKð  ô Ð7¸$Ñ>Ó
?Ð?r2   c                 óê  ‡— g }t        | |«      D ]?  }t        |d«      r |j                  |j                  «       «       Œ/|j	                  |«       ŒA t        |«      dk(  r|d   j                  «       S t        |«      dk(  rddlm}  |«       S |D �cg c]  }t        |d«      sŒ|‘Œ }}|D �cg c]  }t        |d«      sŒ|‘Œ }}t        |«      t        |«      kD  rddl	m
}  ||«      S t        |«      dk(  rddlm}  |«       S t        |d   d«      }	t        |D �
cg c]  }
|
j                  j                  «       ‘Œ c}
|D �
cg c]  }
|
j                  j                  «       ‘Œ c}
«      \  }}d}t        d	„ |D «       «      r>t!        |D �
cg c]  }
|
j"                  ‘Œ c}
«      }|j$                  |j$                  k(  sJ ‚d}t        d
„ |D «       «      r>t!        |D �
cg c]  }
|
j&                  ‘Œ c}
«      }|j$                  |j$                  k(  sJ ‚	 |d   j(                  j                  |dd D �
cg c]  }
|
j(                  ‘Œ c}
«      }i }	 |j3                  d„ |D «       «      g}i }|d   j4                  j7                  «       D ]Z  Št9        ˆfd„|D «       «      sŒ	 t;        j                  |D �cg c]  }|j4                  j=                  ‰g «      ‘Œ  c}d¬«      |‰<   Œ\ i }|d   j@                  j7                  «       D ]Z  Št9        ˆfd„|D «       «      sŒ	 t;        j                  |D �cg c]  }|j@                  j=                  ‰g «      ‘Œ  c}d¬«      |‰<   Œ\  |	||||||||d¬«	      }	 tC        |d   jD                  «      |_#        |S c c}w c c}w c c}
w c c}
w c c}
w c c}
w c c}
w # t*        $ r3}t,        j/                  dt0        › �d¬«       d}t0        r|‚Y d}~�ŒŸd}~ww xY w# t*        $ r Y �Œ—w xY wc c}w # t*        $ r t,        j?                  d‰› d�d¬«       Y �Œ¨w xY wc c}w # t*        $ r t,        j?                  d‰› d�d¬«       Y �Œ\w xY w# t*        $ r Y |S w xY w)a7  
    Concatenate two or more meshes.

    Parameters
    ------------
    a : trimesh.Trimesh
      Mesh or list of meshes to be concatenated
      object, or list of such
    b : trimesh.Trimesh
      Mesh or list of meshes to be concatenated

    Returns
    ----------
    result
      Concatenated mesh
    ÚScener   r   )ÚTrimeshr¡  rb   )ÚconcatenateNc              3   ó8   K  — | ]  }d |j                   v –— Œ y­w)Úface_normalsN©Ú_cache©rs   Úms     r0   ru   zconcatenate.<locals>.<genexpr>  s   è ø€ Ð
7©w¨!ˆ>˜QŸX™XÔ%©wùó   ‚c              3   ó8   K  — | ]  }d |j                   v –— Œ y­w)Úvertex_normalsNr¥  r§  s     r0   ru   zconcatenate.<locals>.<genexpr>  s   è ø€ Ð
9±¨AÐ˜qŸx™xÔ'±ùr©  zfailed to combine visuals T©Úexc_infoc              3   óF   K  — | ]  }t        |j                  «      –— Œ y ­wrq   )r   Úmetadatar§  s     r0   ru   zconcatenate.<locals>.<genexpr>'  s   è ø€ ÐC¹7°aœX a§j¡j×1¹7ùs   ‚!c              3   ó”   •K  — | ]?  }t        |j                  j                  ‰g «      «      t        |j                  «      k(  –— ŒA y ­wrq   )rA   Úvertex_attributesÚgetrI  ©rs   r¨  r|  s     €r0   ru   zconcatenate.<locals>.<genexpr>/  s9   øè ø€ ÐYÑQXÈAŒs�1×&Ñ&×*Ñ*¨3°Ó3Ó4¼¸A¿J¹J»ÕGÑQXùó   ƒAA©Úaxisz)Failed to concatenate `vertex_attribute['z']`c              3   ó”   •K  — | ]?  }t        |j                  j                  ‰g «      «      t        |j                  «      k(  –— ŒA y ­wrq   )rA   Úface_attributesr²  rH  r³  s     €r0   ru   zconcatenate.<locals>.<genexpr>=  s7   øè ø€ ÐTÉGÀqŒs�1×$Ñ$×(Ñ(¨¨bÓ1Ó2´c¸!¿'¹'³lÕBÉGùr´  z'Failed to concatenate `face_attribute['F)	rI  rH  r¤  r«  Úvisualr±  r¸  r¯  Úprocess)$r   r‘  ÚextendÚdumprÚ   rA   rF   rž  r¡  Ú	path.utilr¢  r’  rJ  rI  rH  r1  rB  r¤  rB   r«  r¹  ÚBaseExceptionr   Údebugr#   Úupdater±  r0  rx   r-   r²  Úwarningr¸  r   ÚsourceÚ_source)rL   rM   r¼  rt   r¡  rS  Úis_meshÚis_pathÚconcatenate_pathÚtrimesh_typer¨  rI  rH  r¤  r«  r¹  ÚEr¯  Ú_r±  Úmeshr¸  rÛ   r|  s                          @r0   r¢  r¢  Ô  sW  ø€ ð" €DÜ�1�aŽ[ˆÜ˜Q Ô(à�K‰K˜Ÿ™›Õ!ð �K‰K˜�Nð ô ˆ4ƒy�A‚~à�A‰w�|‰|‹~ÐÜ	ˆT‹�aŠå!á‹yÐáÓB™$�QÔ"3°A°yÕ"AŠq˜$€GÐBÙÓ?™$�QÔ"3°A°vÕ">Šq˜$€GÐ?ô ˆ7ƒ|”c˜'“lÒ"Ý>á Ó(Ð(ä
ˆ7ƒ|�qÒõ 	"á‹yÐô ˜g a™j¨)Ó4€Lô #Ù$+Ó,¡G˜qˆ�‰�‰Õ	 GÑ,ÁwÓ.OÁwÀ!¨q¯w©w¯|©|­~ÀwÑ.Oó�O€Hˆeð
 €LÜ
Ñ
7©wÓ
7Ô7Ü#¹WÓ$E¹W¸ Q§^£^¸WÑ$EÓFˆØ×!Ñ! U§[¡[Ò0Ð0Ð0ð €NÜ
Ñ
9±Ó
9Ô9Ü%ÁÓ&IÁ¸A q×'7Ó'7ÀÑ&IÓJˆØ×#Ñ# x§~¡~Ò5Ð5Ð5ðà˜‘×"Ñ"×.Ñ.À'È!È"Á+Ó/NÁ+¸Q°·³À+Ñ/NÓOˆð €HðØ�_‰_ÑC¹7ÓCÓCÐDˆð
 ÐØ�q‰z×+Ñ+×0Ñ0Ö2ˆäÓYÑQXÓYÕYðÜ)+¯©ÙELÓMÁW¸T�T×+Ñ+×/Ñ/°°RÕ8ÀWÑMÐTUô*Ð! #Ò&ð	 3ð €OØ�q‰z×)Ñ)×.Ñ.Ö0ˆäÓTÉGÓTÕTð	ä')§~¡~ÙCJÓKÁ7¸4�T×)Ñ)×-Ñ-¨c°2Õ6À7ÑKÐRSô(� Ò$ð 1ñ ØØØ!Ø%ØØ+Ø'ØØô
€FðÜ! '¨!¡*×"3Ñ"3Ó4ˆŒð €MùòI CùÚ?ùò* 	-ùÒ.Oùò %Fùò 'Jùò
 0OøÜò Ü�	‰	Ð.¬w¨iÐ8À4ˆ	ÔHØˆÝØˆGõ ûðûô ò Úðüò Nøä ò Ü—‘Ø?À¸uÀCÐHÐSWð ÷ ðüò Løä ò ä—‘Ø=¸c¸UÀ#ÐFÐQUð ÷ ðûô* ò Øà€MðúsÆ   ÂNÂ$NÂ.NÃ NÄ!NÅ!N"
ÆN'ÇN,ÈN6 È4N1ÉN6 ÉO5 Ê"P
Ê5#P
ËP
ÌP:Ì1#P5
ÍP:Í4Q% Î1N6 Î6	O2Î?(O-Ï-O2Ï5	PÐPÐP
Ð
$P2Ð1P2Ð5P:Ð:$Q"Ñ!Q"Ñ%	Q2Ñ1Q2Úfaces_sequenceÚrepairÚonly_watertightÚ	min_facesrÚ   c                 óv  — t        |«      }t        |«      dk(  rg S | j                  j                  t        j
                  «      }| j                  j                  t        j
                  «      }g }g }	g }
g }t	        j                  t        |«      «      }|D �]2  }t	        j                  |«      }t        |«      dk(  rŒ(|j                  j                  dk(  r'|j                  «       sŒR|�%|j                  «       |k  rŒh|�t        |«      |k  rŒy||   }t	        j                  |j                  d«      «      }t	        j                  t        |«      «      ||<   |
j                  | j                   |   «       |j                  ||   «       |	j                  ||   «       |j                  | j"                  j%                  |«      «       �Œ5 t        |	«      dk(  rg S t'        | d«      }|rŽd}	 t	        j(                  |«      }|d   j+                  |dd «      }t3        |	|«      \  }	} ||	|t	        j4                  |
«      |t7        | j8                  «      d
¬«      }t7        | j:                  «      |_        |S |€dgt        |	«      z  }t?        |	||
|«      D ����cg c](  \  }}}} |||||t7        | j8                  «      d
¬«      ‘Œ* }}}}}|D �cg c]"  }tA        |dt7        | j:                  «      «      ‘Œ$ c} |r8|D �cg c],  }t        |j                  «      dk\  xr |jC                  «       ‘Œ. }}n|r|D �cg c]  }|jD                  ‘Œ }}|r"t?        |«      D ��cg c]
  \  }}|sŒ	|‘Œ c}}S |S # t,        $ r t.        j1                  dd¬	«       Y �Œ�w xY wc c}}}}w c c}w c c}w c c}w c c}}w )ax  
    Return a subset of a mesh.

    Parameters
    ------------
    mesh : Trimesh
        Source mesh to take geometry from
    faces_sequence : sequence (p,) int
        Indexes of mesh.faces
    repair
        Try to make submeshes watertight
    only_watertight
        Only return submeshes which are watertight
    min_faces
      Minimum number of faces allowed in a submesh.
    append : bool
        Return a single mesh which has the faces appended,
        if this flag is set, only_watertight is ignored

    Returns
    ---------
    result : Trimesh | list[Trimesh]
      Depending on if `append` is true or not.
    r   rM   Nr>   r¡  r   zfailed to combine visualsTr¬  F)rI  rH  r¤  r¹  r¯  rº  rÃ  r$   )#r�   rA   rH  Úviewr-   r°   rI  rÈ   r@   r&   rY  r1  rV   ÚuniquerE   rÚ   r¤  r¹  Úface_subsetr’  r<  r¢  Ú	Exceptionr   r¿  rJ  rÉ   r   r¯  rÂ  rÃ  r€   ÚsetattrÚ
fill_holesÚis_watertight)rÊ  rË  rÌ  rÍ  rÎ  rÚ   Úoriginal_facesÚoriginal_verticesrH  rI  ÚnormalsÚvisualsÚmaskÚindexÚcurrentrÑ  rÇ  r¹  ÚappendedrÝ   rS  ÚnrÕ   rÛ   Úrrt   Ú
watertightÚws                               r0   Úsubmeshrã  ^  sy  € ôB ˜.Ó)€Nä
ˆ>Ó˜aÒØˆ	ð —Z‘Z—_‘_¤R§Z¡ZÓ0€NØŸ™×*Ñ*¬2¯:©:Ó6Ðà€EØ€HØ€GØ€Gô �9‰9”SÐ*Ó+Ó,€Däˆä—‘˜eÓ$ˆÜˆu‹:˜Š?àØ�;‰;×Ñ˜sÒ"à—9‘9”;ØàÐ$¨¯©«°yÒ)@ØØÐ"¤s¨5£z°IÒ'=Øà  Ñ'ˆÜ—‘˜7Ÿ?™?¨2Ó.Ó/ˆô —y‘y¤ V£Ó-ˆˆV‰Ø�‰�t×(Ñ(¨Ñ/Ô0Ø�‰�T˜'‘]Ô#Ø�‰Ð)¨&Ñ1Ô2à�‰�t—{‘{×.Ñ.¨uÓ5Ö6ð3  ô6 ˆ8ƒ}˜ÒØˆ	ô ˜d IÓ.€LáØˆð	BÜ—h‘h˜wÓ'ˆGØ˜Q‘Z×+Ñ+¨G°A°B¨KÓ8ˆFô ' x°Ó7‰ˆ�%ÙØØÜŸ™ 7Ó+ØÜ˜dŸm™mÓ,Øô
ˆô $ D§K¡KÓ0ˆÔàˆà€Ø�&œ3˜x›=Ñ(ˆô ˜h¨¨w¸Ô@ö
ñ A‰JˆAˆq�!�Qñ 	ØØØØÜ˜dŸm™mÓ,Øö	
ð Að ó 
ñ <BÓB¹6°a„WˆQ�	œ8 D§K¡KÓ0Õ1¸6ÒBáñ EKÓKÁF¸q”c˜!Ÿ'™'“l aÑ'Ò:¨A¯L©L«NÑ:ÀFˆ
ÑKÙ	á/5Ó6©v¨!�a—o“o¨vˆ
Ð6áä! &¨*Ô5Ô;Ñ5‘d�a˜º’Ð5Ò;Ð;à€Møôa ò 	BÜ�I‰IÐ1¸DˆI×Að	Büõ(
ùò Cùò
 Lùò 7ùó <s6   Ç-,M7 Ê-N
Ë'N&Ì1N+Ì<N0Í"
N5Í-N5Í7 NÎNÚrightc                 óþ   — t        | «      dk(  rt        j                  |«      S t        | «      |k  r8t        j                  |«      }|r| |t        | «       d |S | |dt        | «       |S t        j                  | «      S )zÆ
    Parameters
    ------------
    data : (n,)
      1D array
    count : int
      Minimum length of result array

    Returns
    ---------
    padded : (m,)
      1D array where m >= count
    r   N)rA   r-   r›   r@   )r¹   rÐ   rä  Úpaddeds       r0   Úzero_padrç  ê  sx   € ô ˆ4ƒy�A‚~Ü�x‰x˜‹ÐÜ	ˆT‹�UÒ	Ü—‘˜%“ˆÙØ#'ˆF”C˜“I�:�<Ð ð ˆð #'ˆF�;”S˜“YÐØˆä�}‰}˜TÓ"Ð"r2   Úkwargsc                 ód   —  G d„ dt         j                  «      }t        j                  | fd|i|¤ŽS )a=  
    A version of json.dumps that can handle numpy arrays
    by creating a custom encoder for numpy dtypes.

    Parameters
    --------------
    obj : list, dict
      A JSON-serializable blob
    kwargs : dict
      Passed to json.dumps

    Returns
    --------------
    dumped : str
      JSON dump of obj
    c                   ó   — e Zd Zdefd„Zy)újsonify.<locals>.EdgeEncoderrY   c                 óà   — t        |d«      r|j                  «       S t        |d«      r|j                  «       S t        |d«      rt        |«      S t        j
                  j                  | |«      S )Nrã   Ú	timestampÚ__dataclass_fields__)r]   rã   rí  Údataclass_to_dictrà   ÚJSONEncoderÚdefault)ÚselfrY   s     r0   rñ  z$jsonify.<locals>.EdgeEncoder.default  s_   € ô �s˜HÔ%à—z‘z“|Ð#Ü˜˜kÔ*à—}‘}“Ð&Ü˜Ð4Ô5ä(¨Ó-Ð-Ü×#Ñ#×+Ñ+¨D°#Ó6Ð6r2   N)rd   Ú
__module__Ú__qualname__r   rñ  rw   r2   r0   ÚEdgeEncoderrë    s   „ ð	7˜sô 	7r2   rõ  Úcls)rà   rð  Údumps)rY   rè  rõ  s      r0   râ   râ     s/   € ô$7”d×&Ñ&ô 7ô  �:‰:�cÑ5˜{Ð5¨fÑ5Ð5r2   c                 óâ  — t        |t        j                  «      r!t        j                  | |j                  ¬«      S t        | |j
                  «      s|€| S t        | «      r,t        | «      dk(  rt        | d   |j
                  «      r| d   S t        | t        «      rA|j
                  j                  dk(  r(| j                  d«      rddlm} |j                  | «      S |j                  | «      } | S )a"  
    Convert an item to have the dtype of another item

    Parameters
    ------------
    item : any
      Item to be converted
    like : any
      Object with target dtype
      If None, item is returned unmodified

    Returns
    ----------
    result: item, but in dtype of like
    r%   r   r   ÚPolygonÚPOLYGON)Úwkt)ri   r-   r°   r@   r&   rc   r}   rA   rj   rd   r  r  rû  rá   )ÚitemÚlikerû  s      r0   Úconvert_likerþ  *  sÀ   € ô" �$œŸ
™
Ô#Ü�}‰}˜T¨¯©Ô4Ð4ô �$˜Ÿ™Ô'¨4¨<Øˆô �4ÔœS ›Y¨!š^´
¸4À¹7ÀDÇNÁNÔ0SØ�A‰wˆô 	�4œÔØ�N‰N×#Ñ# yÒ0Ø�O‰O˜IÔ&õ 	 à�y‰y˜‹Ðð �>‰>˜$Ó€Dà€Kr2   c           
      ó˜  — ddl }t        j                  | t        j                  d¬«      } t	        | j
                  «      dk(  r:| j
                  d   dk7  rt        d«      ‚| j                  t	        | «      d	f«      } n2t	        | j
                  «      dk7  s| j                  dk(  rt        d
«      ‚| j
                  d   }|dz  dk7  rt        d«      ‚t        |dz  «      }|j                  j                  |¬«      }|j                  j                  t        t        j                  t	        | «      «      | dgt	        | «      z  «      |¬«      S )ar  
    Given a set of axis aligned bounds create an r-tree for
    broad-phase collision detection.

    Parameters
    ------------
    bounds : (n, 2D) or (n, 2, D) float
      Non-interleaved bounds where D=dimension
      E.G a 2D bounds tree:
      [(minx, miny, maxx, maxy), ...]

    Returns
    ---------
    tree : Rtree
      Tree containing bounds by index
    r   NT©r&   rF   rŒ   r   r<   zbounds not (n, 2, dimension)!r>   z"Bounds must be (n, dimension * 2)!zBounds must be (n,dimension*2)!)Ú	dimension)Ú
properties)Úrtreer-   r<  rU   rA   rB   rG   rE   Úsizerƒ   rÜ  ÚPropertyÚIndexr€   rÈ   )rÁ   r  r  r  s       r0   Úbounds_treer  W  s  € ó" ô �X‰X�f¤B§J¡J°TÔ:€FÜ
ˆ6�<‰<Ó˜AÒà�<‰<˜‰?˜aÒÜÐ<Ó=Ð=à—‘¤ V£¨bÐ 1Ó2‰Ü	ˆV�\‰\Ó	˜aÒ	 6§;¡;°!Ò#3ÜÐ=Ó>Ð>ð —‘˜Q‘€IØ�A‰˜!ÒÜÐ:Ó;Ð;Ü�I ‘MÓ"€Ià—‘×%Ñ%°	Ð%Ó:€Jà�;‰;×ÑÜŒB�I‰I”c˜&“kÓ" F¨T¨F´S¸³[Ñ,@ÓAÈjð ó ð r2   rü  c                 ó°   — t        | t        «      rt        | «      S t        | t        «      rt	        | «      S t        t        | «      j                  › d�«      ‚)zâ
    Wrap a string or bytes object as a file object.

    Parameters
    ------------
    item: str or bytes
      Item to be wrapped

    Returns
    ---------
    wrapped : file-like object
      Contains data from item
    z is not wrappable!)ri   rj   r   Úbytesr   rG   r{   rd   )rü  s    r0   Úwrap_as_streamr
  ‚  sJ   € ô �$œÔÜ˜‹~ÐÜ	�Dœ%Ô	 Ü�t‹}ÐÜ
œ˜T›
×+Ñ+Ð,Ð,>Ð?Ó
@Ð@r2   r+  Úsigfigc                 ó4   — t        | |«      \  }}|d|z  z  }|S )aZ  
    Round a single value to a specified number of significant figures.

    Parameters
    ------------
    values : float
      Value to be rounded
    sigfig : int
      Number of significant figures to reduce to

    Returns
    ----------
    rounded : float
      Value rounded to the specified number of significant figures


    Examples
    ----------
    In [1]: trimesh.util.round_sigfig(-232453.00014045456, 1)
    Out[1]: -200000.0

    In [2]: trimesh.util.round_sigfig(.00014045456, 1)
    Out[2]: 0.0001

    In [3]: trimesh.util.round_sigfig(.00014045456, 4)
    Out[3]: 0.0001405
    é
   )Ú
sigfig_int)r+  r  Úas_intÚ
multiplierÚroundeds        r0   Úsigfig_roundr  —  s(   € ô8 $ F¨FÓ3Ñ€FˆJØ˜˜J™Ñ'€Gà€Nr2   c                 ón  — t        j                  | «      j                  d«      } t        j                  |t         j                  ¬«      j                  d«      }|j                  | j                  k7  rt        d«      ‚t        j                  t        | «      «      }t        j                  | «      t        kD  }t        j                  t        j                  t        j                  | |   «      «      «      ||<   ||z
  dz   }| d|z  z  j                  «       j                  t         j                  «      }||fS )a÷  
    Convert a set of floating point values into integers
    with a specified number of significant figures and an
    exponent.

    Parameters
    ------------
    values : (n,) float or int
      Array of values
    sigfig : (n,) int
      Number of significant figures to keep

    Returns
    ------------
    as_int : (n,) int
      Every value[i] has sigfig[i] digits
    multiplier : (n,) float
      Exponent, so as_int * 10 ** multiplier is
      the same order of magnitude as the input
    r>   r%   zsigfig must match identifierr   r  )r-   r@   rE   rÓ   rB   rG   r›   rA   r™   r    Úfloorrù   ÚroundrC  )r+  r  ÚexponentÚnonzeror  r  s         r0   r  r  ¹  så   € ô. �]‰]˜6Ó"×*Ñ*¨2Ó.€FÜ�]‰]˜6¬¯©Ô2×:Ñ:¸2Ó>€Fà‡|�|�v—|‘|Ò#ÜÐ7Ó8Ð8ä�x‰xœ˜F›Ó$€HÜ�f‰f�V‹nœxÑ'€GÜŸ™¤§¡¬"¯&©&°¸±Ó*AÓ!BÓC€HˆWÑà˜FÑ" QÑ&€JØ˜˜J™Ñ'×.Ñ.Ó0×7Ñ7¼¿¹ÓA€Fà�:ÐÐr2   l         Ú	file_typec                 óì  — t        |«      j                  «       }t        | t        «      rt	        | «      } |j                  d«      rÅt        j                  | «      }i }d}|j                  «       D ]—  }||j                  z   t        kD  r,t        j                  d|j                  |j                  «       ŒE||j                  z  }|j                  |d¬«      5 }|j                  «       }ddd«       t!        «      ||j                  <   Œ™ |S |j                  d«      r@ddl}t%        | dd	«      dd
 }	|	t!        |j                  | d¬«      j                  «       «      iS d|dd v r{ddl}
|
j                  | d¬«      }i }|j)                  «       D ]M  }|j+                  «       sŒ|j-                  |«      }|€Œ(t!        |j                  «       «      ||j.                  <   ŒO |S t1        d«      ‚# 1 sw Y   �ŒxY w)ag  
    Given an open file object and a file type, return all components
    of the archive as open file objects in a dict.

    ZIP members are skipped once the total uncompressed size declared by
    the archive exceeds `_ARCHIVE_SKIP_SIZE`. Other formats don't store a
    per-member compressed size so there is nothing to check before reading.

    Parameters
    ------------
    file_obj : file-like
      Containing compressed data.
    file_type : str
      File extension, 'zip', 'tar.gz', etc.

    Returns
    ---------
    decompressed : dict
      Data from archive in format {file name : file-like}.
    r€   r   z7skipping `%s`: declared %d bytes exceeds archive budgetrà  )ÚmodeNÚbz2r3   Úarchive1234éüÿÿÿÚtariúÿÿÿ)Úfileobjr  zUnsupported type passed!)rj   Úlowerri   r	  r   re   ÚzipfileÚZipFileÚinfolistÚ	file_sizeÚ_ARCHIVE_SKIP_SIZEr   rÁ  ÚfilenameÚopenr[   r
  r  ÚgetattrÚtarfileÚ
getmembersÚisfileÚextractfiler3   rG   )rä   r  ÚarchiverÛ   ÚtotalÚinfoÚsrcr¹   r  r3   r)  s              r0   Ú
decompressr1  ä  sÅ  € ô0 �I“×$Ñ$Ó&€IÜ�(œEÔ"Ü˜8Ó$ˆà×Ñ˜%Ô Ü—/‘/ (Ó+ˆØˆð ˆØ×$Ñ$Ö&ˆDØ�t—~‘~Ñ%Ô(:Ò:Ü—‘ØMØ—M‘MØ—N‘Nôð
 Ø�T—^‘^Ñ#ˆEØ—‘˜d¨�Ô-°Ø—x‘x“z�÷ .ä$2°4Ó$8ˆF�4—=‘=Ò!ð 'ð ˆØ×Ñ˜%Ô Ûô �x ¨Ó7¸¸Ð<ˆØ”n S§X¡X¨h¸S XÓ%A×%FÑ%FÓ%HÓIÐJÐJØ�	˜"˜#�ÑÛà—,‘, x°c�,Ó:ˆØˆØ×&Ñ&Ö(ˆDØ—;‘;”=ØØ×%Ñ% dÓ+ˆCØˆ{ØÜ .¨s¯x©x«zÓ :ˆF�4—9‘9Òð )ð ˆÜ
Ð/Ó
0Ð0÷/ .Ñ-ús   ÃG)Ç)G3	r/  c                 ó|  — t        «       }t        j                  |fdt        j                  dœ|¤Ž5 }| j	                  «       D ]@  \  }}t        |t        t        f«      r|}n|j                  «       }|j                  ||«       ŒB 	 ddd«       |j                  d«       |j                  «       }|S # 1 sw Y   Œ,xY w)a1  
    Compress data stored in a dict.

    Parameters
    -----------
    info : dict
      Data to compress in form:
      {file name in archive: bytes or file-like object}
    kwargs : dict
      Passed to zipfile.ZipFile
    Returns
    -----------
    compressed : bytes
      Compressed file data
    râ  )r  ÚcompressionNr   )r   r!  r"  ÚZIP_DEFLATEDÚitemsri   rj   r	  r[   Úwritestrrè   )r/  rè  rä   Úzipperr3   Údata_or_filer¹   Ú
compresseds           r0   Úcompressr:  *  sª   € ô& ‹y€HÜ	�‰Øð
Ø¬×(<Ñ(<ñ
Ø@Fò
à	Ø"&§*¡*¦,ÑˆD�,Ü˜,¬¬e¨Ô5Ø#‘ð $×(Ñ(Ó*�Ø�O‰O˜D $Õ'ñ #/÷
ð ‡M�M�!ÔØ—‘“€JØÐ÷
ð 
ús   ²AB2Â2B;Ú	file_nameÚspecialc                 ó¸   — t        | «      } |€ddg}| j                  t        |«      «      r|D ]  }| j                  |«      sŒ|c S  | j                  d«      d   S )a‘  
    Find the file extension of a file name, including support for
    special case multipart file extensions (like .tar.gz)

    Parameters
    ------------
    file_name : str
      File name
    special : list of str
      Multipart extensions
      eg: ['tar.bz2', 'tar.gz']

    Returns
    ----------
    extension : str
      Last characters after a period, or
      a value from 'special'
    ztar.bz2ztar.gzr  r>   )rj   re   r‚   r„  )r;  r<  Úends      r0   Úsplit_extensionr?  M  sa   € ô& �I“€Ià€Ø˜hÐ'ˆØ×Ñœ% ›.Ô)ÛˆCØ×!Ñ! #Õ&Ø’
ð ð �?‰?˜3Ó Ñ#Ð#r2   Ústripsc                 ó|  — t        j                  | D �cg c]  }t        |«      ‘Œ c}t         j                  ¬«      }t        j                  | t         j                  ¬«      }t        j                  |dd |dd |dd gt         j                  ¬«      j
                  }t        | «      dk(  r#t        j                  |ddd…   «      |ddd…<   |S t        j                  |«      dd }t        j                  t        |«      t        ¬«      }d||dz
  <   d||dz
  <   ||   }t        j                  dt        j                  |dz
  «      «      }t        j                  |d   t        ¬«      }t        t        |«      dz
  «      D ]  }d	|||   dz   ||dz       ddd…<   Œ t        j                  ||   «      ||<   |S c c}w )
aü  
    Convert a sequence of triangle strips to (n, 3) faces.

    Processes all strips at once using np.concatenate and is significantly
    faster than loop-based methods.

    From the OpenGL programming guide describing a single triangle
    strip [v0, v1, v2, v3, v4]:

    Draws a series of triangles (three-sided polygons) using vertices
    v0, v1, v2, then v2, v1, v3  (note the order), then v2, v3, v4,
    and so on. The ordering is to ensure that the triangles are all
    drawn with the same orientation so that the strip can correctly form
    part of a surface.

    Parameters
    ------------
    strips: (n,) list of (m,) int
      Vertex indices

    Returns
    ------------
    faces : (m, 3) int
      Vertex indices representing triangles
    r%   Néþÿÿÿr   r>   r<   Fr   T)r-   r<  rA   rÓ   r¢  rš   ÚfliplrrA  r�   ÚboolrÚ   r›   r—  )r@  rt   ÚlengthsÚblobÚtriÚlength_indexÚkeepÚflips           r0   Útriangle_strips_to_facesrK  k  s‘  € ô< �h‰h©Ó/© 1œ˜A�¨Ñ/´r·x±xÔ@€Gô �>‰>˜&¬¯©Ô1€Dô �(‰(�D˜˜"�I˜t A b˜z¨4°°¨8Ð4¼B¿H¹HÔ
E×
GÑ
G€Cô ˆ6ƒ{�aÒä—I‘I˜c ! $ Q $™iÓ(ˆˆAˆDˆqˆD‰	Øˆ
ô —9‘9˜WÓ% c rÐ*€LÜ�7‰7”3�s“8¤4Ô(€DØ"€Dˆ˜Ñ	ÑØ"€Dˆ˜Ñ	ÑØ
ˆd‰)€Cô —9‘9˜Q¤§	¡	¨'°A©+Ó 6Ó7€LÜ�8‰8�L Ñ$¬DÔ1€DÜ”3�|Ó$ qÑ(Ö)ˆØ?Cˆˆ\˜!‰_˜qÑ  <°°A±Ñ#6Ð7¹¸!¸Ò<ð *ä—	‘	˜#˜d™)Ó$€Cˆ�Ià€Jùò= 0s   ”F9Úfansc                 óî   — | D �cg c]K  }t        j                  |d   t        j                  t        |«      dz
  t        ¬«      z  |dd |dd g«      ‘ŒM }}t        j
                  |t        ¬«      S c c}w )zþ
    Convert fans of m + 2 vertex indices in fan format to m triangles

    Parameters
    ----------
    fans: (n,) list of (m + 2,) int
      Vertex indices

    Returns
    -------
    faces: (m, 3) int
      Vertex indices representing triangles
    r   r<   r%   r   r>   N)r-   Ú	transposer�   rA   rƒ   r¢  )rL  ÚfanrH  s      r0   Útriangle_fans_to_facesrP  ª  sv   € ñ& óáˆCô 	�‰�c˜!‘fœrŸw™w¤s¨3£x°!¡|¼3Ô?Ñ?ÀÀQÀrÀÈCÐPQÐPRÈGÐTÕUØð 
ð ô �>‰>˜%¤sÔ+Ð+ùò	s   …AA2Útupc                 ó  — | D �cg c]  }t        |«      dkD  sŒ|‘Œ }}t        |«      dk(  rt        j                  |d   «      S t        |«      dk(  rt        j                  g «      S t        j                  |«      S c c}w )a$  
    A thin wrapper for numpy.vstack that ignores empty lists.

    Parameters
    ------------
    tup : tuple or list of arrays
      With the same number of columns

    Returns
    ------------
    stacked : (n, d) array
      With same number of columns as
      constituent arrays.
    r   r   )rA   r-   r@   r<  rÉ   )rQ  rt   Ú	stackables      r0   rB  rB  Â  so   € ñ   Ó.™C�q¤3 q£6¨A£:’˜C€IÐ.ä
ˆ9ƒ~˜ÒÜ�}‰}˜Y q™\Ó*Ð*ä	ˆY‹˜1Ò	Ü�x‰x˜‹|Ðä�9‰9�YÓÐùò /s
   …A=™A=Ústuffc                 ó:  — dt        | dd«      v }t        |t        «      }t        |t        «      }|r#|r!| j	                  |j                  |«      «       n6|s#|r!| j	                  |j                  |«      «       n| j	                  |«       | j                  «        |S )aÏ  
    If a file is open in binary mode and a
    string is passed, encode and write.

    If a file is open in text mode and bytes are
    passed decode bytes to str and write.

    Assumes binary mode if file_obj does not have
    a 'mode' attribute (e.g. io.BufferedRandom).

    Parameters
    -----------
    file_obj : file object
      With 'write' and 'mode'
    stuff :  str or bytes
      Stuff to be written
    encoding : str
      Encoding of text
    rM   r  )r(  ri   rj   r	  r\   Úencoderm  Úflush)rä   rT  ri  Úbinary_fileÚstring_stuffÚbinary_stuffs         r0   Úwrite_encodedr[  Ý  s~   € ð0 œ ¨6°3Ó7Ð7€KÜ˜e¤SÓ)€LÜ˜e¤UÓ+€Lá‘|Ø�‰�u—|‘| HÓ-Õ.Ù™\Ø�‰�u—|‘| HÓ-Õ.à�‰�uÔØ‡N�NÔØ€Lr2   Úlengthc                 óp   — t        j                  t        j                  d«      d¬«      j                  d|  S )z÷
    Generate a random alphaNumber unique identifier
    using UUID logic.

    Parameters
    ------------
    length : int
      Length of desired identifier

    Returns
    ------------
    unique : str
      Unique alphaNumber identifier
    é€   r$   )rƒ   ÚversionN)ÚuuidÚUUIDr.   ÚgetrandbitsÚhex)r\  s    r0   Ú	unique_idrd  	  s-   € ô �9‰9œ×+Ñ+¨CÓ0¸!Ô<×@Ñ@ÀÀ&ÐIÐIr2   r¡   Úepsilonc                 ó   — t        j                  | t         j                  d¬«      } | j                  dk7  rt	        d«      ‚t         j
                  j                  | «      }||k  rt        j                  d«      S | |z  } t        j                  | d    | d   dg«      }t         j
                  j                  |«      }||k  rBt        j                  | d	    | d   dg«      }|t         j
                  j                  |«      z  }n||z  }t        j                  | |«      }t        j                  ||| gt         j                  ¬
«      }t        rÁt        j                  t        j                  || «      «      dk  sJ ‚t        j                  t        j                  || «      «      dk  sJ ‚t        j                  t        j                  ||«      «      dk  sJ ‚t        j                  t         j
                  j                  |d¬«      d«      sJ ‚|S )a°  
    Generate an arbitrary basis (also known as a coordinate frame)
    from a given z-axis vector.

    Parameters
    ------------
    z : (3,) float
      A vector along the positive z-axis.
    epsilon : float
      Numbers smaller than this considered zero.

    Returns
    ---------
    x : (3,) float
      Vector along x axis.
    y : (3,) float
      Vector along y axis.
    z : (3,) float
      Vector along z axis.
    Tr   )rŒ   zz must be (3,) float!rŒ   r   r   r˜   r<   r%   r!   rµ  r=   )r-   r<  rU   rB   rG   ÚlinalgrH   ÚeyeÚcrossr#   r™   rD   Úallclose)r¡   re  Úz_normrŸ   Úx_normr    rÛ   s          r0   Úgenerate_basisrm  	  s™  € ô, 	�‰�œ"Ÿ*™*¨4Ô0€Aà‡w�w�$‚ÜÐ0Ó1Ð1ä�Y‰Y�^‰^˜AÓ€FØ�ÒÜ�v‰v�a‹yÐð ˆ�K€Aä
�‰�1�Q‘4�%˜˜1™˜sÐ#Ó$€Aä�Y‰Y�^‰^˜AÓ€FØ�Òô �H‰H�q˜‘t�e˜Q˜q™T 3Ð'Ó(ˆØ	ŒR�Y‰Y�^‰^˜AÓÑ‰ð 	
ˆV‰ˆä
�‰��A‹€Aä�X‰X�q˜!˜Q�i¤r§z¡zÔ2€Fåä�v‰v”b—f‘f˜Q “lÓ# dÒ*Ð*Ð*Ü�v‰v”b—f‘f˜Q “lÓ# dÒ*Ð*Ð*Ü�v‰v”b—f‘f˜Q “lÓ# dÒ*Ð*Ð*ä�{‰{œ2Ÿ9™9Ÿ>™>¨&°q˜>Ó9¸3Ô?Ð?Ð?à€Mr2   Úatolc                 óF   — | |z
  }t        j                  || kD  ||k  «      S )aû  
    A replacement for np.isclose that does fewer checks
    and validation and as a result is roughly 4x faster.

    Note that this is used in tight loops, and as such
    a and b MUST be np.ndarray, not list or "array-like"

    Parameters
    ------------
    a : np.ndarray
      To be compared
    b : np.ndarray
      To be compared
    atol : float
      Acceptable distance between `a` and `b` to be "close"

    Returns
    -----------
    close : np.ndarray, bool
      Per-element closeness
    )r-   r�   )rL   rM   rn  Údiffs       r0   Úiscloserq  R	  s(   € ð4 ˆq‰5€DÜ�>‰>˜$ $ ™,¨¨t©Ó4Ð4r2   c                 ó\   — t        t        t        j                  | |z
  «      «      |k  «      S )a|  
    A replacement for np.allclose that does few checks
    and validation and as a result is faster.

    Parameters
    ------------
    a : np.ndarray
      To be compared
    b : np.ndarray
      To be compared
    atol : float
      Acceptable distance between `a` and `b` to be "close"

    Returns
    -----------
    bool indicating if all elements are within `atol`.
    )rD  Úfloatr-   Úptp)rL   rM   rn  s      r0   rj  rj  p	  s%   € ô& ””b—f‘f˜Q ™U“mÓ$ tÑ+Ó,Ð,r2   c                   ó¨   — e Zd ZdZdedef   ddfd„Zdededef   fd„Zded	ede	f   ddfd
„Z
dee   fd„Zdefd„Zde	defd„Zdede	de	defd„Zy)ÚFunctionRegistrya  
    Non-overwritable mapping of string keys to functions.

    This allows external packages to register additional implementations
    of common functionality without risk of breaking implementations provided
    by trimesh.

    See trimesh.voxel.morphology for example usage.
    rè  .r*   Nc                 óL   — i | _         |j                  «       D ]
  \  }}|| |<   Œ y rq   )Ú_dictr5  )rò  rè  rÜ   rÝ   s       r0   Ú__init__zFunctionRegistry.__init__‘	  s&   € ØˆŒ
Ø—L‘L–N‰DˆAˆqØˆD�ŠGñ #r2   r|  c                 ó    — | j                   |   S rq   ©rx  ©rò  r|  s     r0   rn   zFunctionRegistry.__getitem__–	  s   € Ø�z‰z˜#‰Ðr2   Úvaluec                 ó®   — t        |t        «      st        d|›�«      ‚|| v rt        d|› �«      ‚t	        |«      st        d«      ‚|| j
                  |<   y )Nzkey must be a string, got z%Cannot set new value to existing key z'Cannot set value which is not callable.)ri   rj   rG   ÚKeyErrorÚcallablerx  )rò  r|  r}  s      r0   Ú__setitem__zFunctionRegistry.__setitem__™	  sY   € Ü˜#œsÔ#ÜÐ9¸#¸ÐAÓBÐBØ�$‰;ÜÐBÀ3À%ÐHÓIÐIÜ˜ŒÜÐFÓGÐGØˆ�
‰
�3Šr2   c                 ó,   — t        | j                  «      S rq   )Úiterrx  ©rò  s    r0   ro   zFunctionRegistry.__iter__¢	  s   € Ü�D—J‘JÓÐr2   c                 ó,   — t        | j                  «      S rq   )rA   rx  r„  s    r0   Ú__len__zFunctionRegistry.__len__¥	  s   € Ü�4—:‘:‹Ðr2   c                 ó   — || j                   v S rq   r{  r|  s     r0   Ú__contains__zFunctionRegistry.__contains__¨	  s   € Ø�d—j‘jÐ Ð r2   Úargsc                 ó   —  | |   |i |¤ŽS rq   rw   )rò  r|  r‰  rè  s       r0   Ú__call__zFunctionRegistry.__call__«	  s   € Øˆt�C‰y˜$Ð) &Ñ)Ð)r2   )rd   ró  rô  Ú__doc__r   r   ry  rj   rn   Úobjectr�  r   ro   rƒ   r†  rD  rˆ  r‹  rw   r2   r0   rv  rv  †	  s²   „ ñð ¨#¨s¨(Ñ!3ð ¸ó ð
˜sð  x°°S°Ñ'9ó ð ˜sð  ¨8°C¸°KÑ+@ð  ÀTó  ð ˜( 3™-ó  ð˜ó ð! ð !¨4ó !ð*˜Cð *¨ð *¸&ð *ÀSô *r2   rv  Úinitialc           	      ó  — t        | t        «      r| S 	 | j                  |«      S # t        $ rZ ddlm}  || dd «      }t        j                  dj                  ||d   |d   «      «       | j                  |d   xs |d¬	«      cY S w xY w)
a{  
    Try to decode byte input as a string.

    Tries initial guess (UTF-8) then if that fails it
    uses charset_normalizer to try another guess before failing.

    Parameters
    ------------
    text : bytes
      Data that might be a string
    initial : str
      Initial guess for text encoding.

    Returns
    ------------
    decoded : str
      Data as a string
    r   )ÚdetectNiè  z&Data not {}! Trying {} (confidence {})ri  Ú
confidenceÚignore©Úerrors)	ri   rj   rm  ÚUnicodeDecodeErrorÚcharset_normalizerr�  r   r¿  r[  )r  rŽ  Úcharset_normalizer_detectr�  s       r0   Údecode_textr˜  ¯	  s˜   € ô( �$œÔØˆðKà�{‰{˜7Ó#Ð#øÜò KåJñ +¨4°°¨;Ó7ˆä�	‰	Ø4×;Ñ;Ø˜ 
Ñ+¨V°LÑ-Aóô	
ð �{‰{˜6 *Ñ-Ò8°Àˆ{ÓJÒJðKús   ”% ¥A BÂBc                 ó²   — t        | d«      r"| j                  dd¬«      j                  d«      S t        | d«      r| j                  dd¬«      S t        | «      S )zç
    Force a string or other to ASCII text ignoring errors.

    Parameters
    -----------
    text : any
      Input to be converted to ASCII string

    Returns
    -----------
    ascii : str
      Input as an ASCII string
    rV  Úasciir’  r“  rm  )r]   rV  rm  rj   )r  s    r0   Úto_asciir›  Û	  sS   € ô ˆt�XÔà�{‰{˜7¨8ˆ{Ó4×;Ñ;¸GÓDÐDÜ	��xÔ	 à�{‰{˜7¨8ˆ{Ó4Ð4äˆt‹9Ðr2   Ú
return_allc                 ó´  — t        j                  | t         j                  ¬«      } t        | j                  «      dk7  s| j                  d   dk7  rt        d«      ‚t        j                  | dd…ddgf   | dd z  j                  Ž }|j                  «       dz  }|d	k  }|s|S | dd | dd z   |j                  d
«      z  j                  d¬«      d|z  z  }|||fS )a¹  
    Check if connected 2D points are counterclockwise.

    Parameters
    -----------
    points : (n, 2) float
      Connected points on a plane
    return_all : bool
      Return polygon area and centroid or just counter-clockwise.

    Returns
    ----------
    ccw : bool
      True if points are counter-clockwise
    area : float
      Only returned if `return_centroid`
    centroid : (2,) float
      Centroid of the polygon.
    r%   r<   r   z only defined for `(n, 2)` pointsNr>   r   g       @r˜   r?   rµ  g      @)
r-   r<  rU   rA   rB   rG   Úsubtractrš   rV   rE   )r¼   rœ  ÚproductÚareaÚccwÚcentroids         r0   Úis_ccwr£  ó	  sç   € ô( �X‰X�f¤B§J¡JÔ/€Fä
ˆ6�<‰<Ó˜AÒ §¡¨a¡°AÒ!5ÜÐ;Ó<Ð<ô �k‰k˜F 3 B 3¨¨A¨ ;Ñ/°&¸¸°*Ñ<×?Ñ?Ð@€Gà�;‰;‹=˜3Ñ€Dà
�‰*€CáØˆ
ð ˜˜�˜v a b˜zÑ)¨W¯_©_¸WÓ-EÑE×JÑJÐPQÐJÓRØˆd‰
ñ€Hð ��hÐÐr2   rê   ÚcontainsÚcountsc                 ó¾  — | �t        | «      dkD  r| |vr| S |€d}n|j                  | d«      }| �Pt        | «      dkD  rB| dz   }| j                  dd«      }t        |«      dk(  r|dk(  r	 t        |d   «      }|d   dz   }nd}t        |dz   d|z   t        |«      z   «      D ]"  }|j                  |«      }||vsŒ|�||| <   |c S  t        d«      ‚# t        $ r Y ŒYw xY w)aA  
    Deterministically generate a unique name not
    contained in a dict, set or other grouping with
    `__includes__` defined. Will create names of the
    form "start_10" and increment accordingly.

    Parameters
    -----------
    start : str
      Initial guess for name.
    contains : dict, set, or list
      Bundle of existing names we can *not* use.
    counts : None or dict
      Maps name starts encountered before to increments in
      order to speed up finding a unique name as otherwise
      it potentially has to iterate through all of contains.
      Should map to "how many times has this `start`
      been attempted, i.e. `counts[start]: int`.
      Note that this *will be mutated* in-place by this function!

    Returns
    ---------
    unique : str
      A name that is not contained in `contains`
    r   z_{}rÉ  r   r<   zgeometry_{}z Unable to establish unique name!)rA   r²  Úrsplitrƒ   r¾  r—  r[  rG   )rê   r¤  r¥  Ú	incrementr4  r„  rt   Úchecks           r0   Úunique_namerª  
  s  € ð> ÐœS ›Z¨!š^°¸XÑ0EØˆð €~Ø‰	à—J‘J˜u aÓ(ˆ	ØÐœS ›Z¨!š^Ø˜E‘Mˆ	à—‘˜S !Ó$ˆÜˆu‹:˜Š?˜y¨Aš~ðô    a¡›M�	à! !™H uÑ,‘	ð "ˆ	ô �9˜q‘= ! i¡-´#°h³-Ñ"?Ö@ˆØ× Ñ  Ó#ˆØ˜Ò ØÐ!Ø !��u‘ØŠLð Aô Ð7Ó
8Ð8øô !ò Ùðús   Á)C Ã	CÃCrq   )FN)F)Ú Ú
é   rT  )Nrk  )rn  )Ú#r¬  )r$   )r*   ztrimesh.parent.Geometry)TFNF)T)r   )é   )gê-�™—q=)r!   )šrŒ  Úabcrk  rØ   rà   r   r.   ÚshutilÚtimer`  rR   r!  Úcollections.abcr   r   r   r   r   r   r	   r
   rF   r   Údataclassesr   rï  Úior   r   Útypingr   Únumpyr-   Ú	iterationr   Útypedr   r   r   r   r   r   r   r   r   r   r   r   Útrimesh.parentÚtrimeshr-  rd   r   r(  Ú__annotations__ÚABCÚnowÚwhichrs  ÚfinforU   Ú
resolutionr    r"   r#   rD  rh  r'   r°   Úflagsr/   r,   Ú	Generatorr1   rj   r7   rK   rX   r_   r�  rg   rk   r}   rƒ   r‚   r…   r�   r‡   r•   r£   r­   r¶   rg  Ú	multi_dotr&   r¸   r»   rÀ   rÎ   rÖ   rÙ   rÞ   rã   rï   rô   rü   r  ÚHandlerr9  r=  ÚfloatingÚintegerrJ  ra  rh  Ú	DTypeLikerx  ry   r~  rˆ  rŽ  r‘  r{   rœ  r’  r¢  rã  rç  râ   rþ  r  r	  r
  r  rÓ   r  r%  r1  r:  r?  rK  rP  rB  r[  rd  rm  Úbool_rq  rj  rv  r˜  r›  r£  rª  rw   r2   r0   Ú<module>rÊ     s®
  ðòó Û Û Û Û Û Û Û Û Û Û ÷	÷ 	ó 	õ Ý 3ß  Ý  ã å ÷÷ ÷ ó ñ$ Ûð (�g×'Ñ'¨Ó1€€W‡^�^Ó 1à	‡g�g€Ø
‡i�i€Ø�‰€ñ ˜˜Ÿ™ §¡Ó,×7Ñ7¸#Ñ=Ó>€ˆ%Ó >à€	ˆ5Ó à€ˆÓ ð ˜Ÿ™˜q¨¯
©
Ô3€	ˆ2�:‰:Ó 3Ø$€	‡��Ñ ð —)‘)×'Ñ'Ó)€ñ'˜4ð '¨2¯9©9×+>Ñ+>ó 'ð0'�Sð '˜Tó 'ð, Ø"ñ8Øð8àð8ð �t‰|ó8ðv)�ð )˜yð )¨R¯Z©Zó )ð"9�ð 9˜ó 9ð">�Fð >˜tó >ð& �6ð  ˜dó  ð"�Sð ˜Tó ðF ñZØ	�3‰ðZà�C˜%  S ™/Ñ)Ñ*ðZð ðZð 
ó	Zðz�sð ˜tó ð4 ñJØðJàóJðZ 9ð °¸2¿:¹:Ñ1Fó ð83 9ð 3°¸2¿:¹:Ñ1Fó 3ð0&�x ‘}ó &ðR �I‰I×Ñ€	ð3-�Ið 3- )ð 3-°·
±
¸5À¹:ÀrÇxÁxÐPSÁ}Ð;TÑ0Uó 3-ðl9�9˜S‘>ð 9 i°·
±
Ñ&;ó 9ð8 ñ(Øð(àð(ð ˆr�z‰zÑ˜U 9¨R¯Z©ZÑ#8¸$Ð#>Ñ?Ñ?ó(ðV˜	ð ¨°)Ñ);ð À	È"Ï*É*Ñ@Uó ð>˜)ð ¨G°iÑ,?ð ÀIÈbÏjÉjÑDYó ð<Ø�x  h° mÑ 4Ñ5Ñ5ðà×Ñ˜X t˜^Ñ,óð0�ð ˜Có ð&˜Vð ¨ó ð$˜fð ¨ó ñ(˜xð °W¸t±^ð Èsó ð* —]‘]Ø&*Ø15ØØ!Ø&*Øñx4Øðx4à�_‰_˜tÑ#ðx4ð ˜Ÿ™Ñ'¨$Ñ.ðx4ð ð	x4ð
 ðx4ð ˜‰}˜tÑ#ðx4ð ðx4ð 
óx4ðv.G˜ð .G wó .Gðb.Ø˜9Ñ%ð.à˜	Ñ"ð.ð ˆ9�R—[‘[Ñ! 9¨R¯Z©ZÑ#8Ð8Ñ9ó.ðf ØØØñQØðQàðQð ðQð ð	Qð
 ðQð 	óQðl ØØØñZØðZàðZð ðZð ð	Zð
 ðZð 	óZð~ )-Øñ*Øð*à�9‰9×Ñ Ñ%ð*ð ð*ð ˆS�#ˆXÑó	*ñ\�t˜C ˜H‘~ð °ð À4ÈÈSÈÁ>ó ñB*˜ð *¨#ð *¸sð *Ècó *ðZ$˜i¨$¨s°C¨x©.Ñ8ð $¸Wó $ðN˜6ð ¨¨t°C©y©ð ¸Tó ñ6=�Fð = 7ð =°4¸±:ó =ð@�Fð @ #ð @¨$ó @ô6GðZ Ø!Ø $ØñIà˜YÑ'ðIð ðIð ð	Ið
 ˜‰~ðIð óIñX#�7ð # 7ð #°4ð #À7ó #ð6"6�ð "6 3ð "6¨3ó "6òJ*ðZ(˜	ð ( có (ðVA˜˜u™ð A¨°GÑ);ó Añ*˜ð ¨Ið ¸iÈÏ
É
Ñ>Só ðD$Øð$Ø(ð$à
ˆ9�R—X’XÑ 	¨"¯*©*Ñ 5Ð5Ñ6ó$ðP "Ð ðC1Ø�f‰nðC1àðC1ð 
ˆ#ˆv˜‰}Ð
ÑóC1ðL Ø
�#�s˜U‘{ VÑ+Ð+Ñ
,ð àð ð ó ñF$˜sð $¨X°c©]¸TÑ-Að $ÈSó $ð<<Ø˜ Ñ+Ñ+ð<àˆr�xŠxÑó<ð~,Ø
�9Ñ
ð,àˆr�xŠxÑó,ð0 �h˜yÑ)ð  ¨gó  ð< ñ#Øð#à�‰;ð#ð ð#ð 	ˆ5�[ó	#ñLJ�gð J só Jñ$:�ið :¨%ð :¸IÀbÇjÁjÑ<Qó :ð@ ñ5Ø�Ñð5à�Ñð5ð ð5ð ‡X‚X�˜ŸšÑ!Ñ!ó	5ñ<-�˜Ñ ð - V¨gÑ%5ð -¸Xð -ÐQUó -ô,&*�w˜s H¨S°#¨XÑ$6Ð6Ñ7ô &*ñR)K�c˜E‘kð )K¨Cð )K¸có )KðX�3ð ˜3ó ñ0(�9ð (¨$ó (ð\ 6:ñB9Ø�‰:ðB9à˜‰oðB9ð ˜3 ™: s˜?Ñ+¨dÑ2ðB9ð 	ô	B9r2   