
    l0j                       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ZddlZddlmZ ddlmZmZ ddlmZ ddlZ ej        d          Zej        Ze
j
        Zej        Z ej        ej                  j        dz  ZdZ d	Z! ej"        d
ej                  Z#d	e#j$        d<   de%de&fdZ'd]dZ(de)fdZ*d Z+d Z,de&fdZ-de&fdZ.de&fdZ/d^de&de&fdZ0d Z1d^dZ2d Z3d Z4d Z5	 ej6        j7        Z7n## e8$ r e9                    d           d Z7Y nw xY wd  Z:d! Z;d^d"Z<d# Z=d$ Z>d% Z?d& Z@d' ZAd( ZBd_deCfd)ZDejE        ddd*d*dfd+ZFd, ZGd- ZHd`d2ZI	 d`d3ZJdad5ZKdbd7ZLdcd9ZMd: ZNd; ZOddd<ZPd= ZQ	 d_ded>         fd?ZR	 ded@ZSdfdAZTdB ZUdC ZVdD ZWdE ZXdgdGZYdH ZZdI Z[dJ Z\d_dKZ]dL Z^dM Z_dN Z`dbdOZadhdQZbdidSZcdjdTe)fdUZddjdTe)fdVZe G dW dXe          ZfdbdYZgdZ Zhd^d[Zid_d\ZjdS )kz
util.py
-----------

Standalone functions which require only imports from numpy and the
standard library.

Other libraries may be imported must be wrapped in try/except blocks
or imported inside of a function
    N)Mapping)BytesIOStringIO)Uniontrimeshd   :0yE>F   dtype	WRITEABLEnamereturnc                 V    t           j        dk    rddlm} n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_spec)find_loaderN)sysversion_infoimportlib.utilr   pkgutilr   )r   r   s     O/home/wildlama/miniconda3/envs/lam/lib/python3.11/site-packages/trimesh/util.py
has_moduler   6   sN     7"",,,,,,, 	5444449T??$&&    c                 :   t          j        |           } |t          }t          | j                  dk    rht          j        t          j        | | z  dg| j        d         z                      }||k    }||xx         dz  cc<   | |                    d          z  }nqt          | j                  dk    rJt          j        t          j        | |                     }||k    }|r| |z  }n$|                                 }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`
    N         ?   r    r   z vectors must be (n, ) or (n, d)!)
np
asanyarrayTOL_ZEROlenshapesqrtdotreshapecopy
ValueError)vectorscheck_valid	thresholdnormvalidunits         r   unitizer2   O   s$   * mG$$G 	
7=Q wrvg/#q9I1IJJKKy Ug...	W]		q	 	 wrvgw//00y  	"T>DD<<>>DD;<<< "E{E!!Kr   c                    t          j        dt          d           t          j        | t          j                  } t          j        |t          j                  }t          j        | |z
  dz                                            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#   float64r'   sumabs     r   	euclideanr>      s|     M	1 $    	arz***A
arz***A7QUqL%%''(((r   c                 B    t          | d          p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objs    r   is_filerF      s#     3873#8#88r   c                 d    | j         j        }t          | d          o|                    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__rC   endswithrE   r   s     r   
is_pathlibrN      s/     =!D3
##=f(=(==r   c                 ,    t          | t                    S )z
    Check if an object is a string.

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

    Returns
    ------------
    is_string : bool
        True if obj is a string
    )
isinstancestrrD   s    r   	is_stringrR      s     c3r   c                 f    | dS t          |           rt          |           dk    r
| d         dS dS )a  
    Check to see if an object is None or not.

    Handles the case of np.array(None) as well.

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

    Returns
    -------------
    is_none : bool
        True if obj is None or numpy None-like
    NTr   r   F)is_sequencer%   rD   s    r   is_nonerU      s>      {t3 CHHMMc!fnt5r   c                 2    t           d           rt           d          pt           d          }|o,t           fdt          t          t          fD                       }|ot                     j        dv}t           d          r|o
 j        dk    }|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   :   K   | ]}t          |           V  d S N)rP   .0irE   s     r   	<genexpr>zis_sequence.<locals>.<genexpr>   s0      GG*S!,,,GGGGGGr   )
PointCloudr&    )rC   alldictsetrQ   typerK   r&   )rE   seqs   ` r   rT   rT      s     sG$$$Dm)D)D ZJ JC
 
G#GGGGtS#6FGGGGGC 
:$s))$N:C sG &%ci2oJr   allow_zerosc                 @   t          | d          r%t          | j                  t          |          k    rdS t          |           dk    rd|v rdS t          | j        |          D ]7\  }}t	          |          r||v r dS |dk     r|dk    r|s dS .||k    r dS 8dS )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
    r&   Fr   r    T)rC   r%   r&   ziprT   )rE   r&   rg   r^   targets        r   is_shaperk     s    b 3   C	NNc%jj$@$@u 3xx1}}ut
 E**  	6v 	F{{uu A::Avvkv uu Q;;55 
 4r   c                     t          |           r!t          j        t          |                     S t          j        | 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
    )rT   r"   arraylistrD   s    r   make_sequencero   Z  s:    $ 3 xS		"""xr   c           
         t          j        | t           j                  } t          | d          r| t           k     }t          j        t          j        || t          k                        }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          k                        }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	          | |                    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   r   zvectors must be (n, 3)!r!   )r"   r#   r9   rk   r$   logical_not
logical_oronesr%   logical_andr+   r)   )r,   return_signnegativezerosignsorienteds         r   vector_hemispherer|   r  s   8 mG2:666G!! !4 hY&~bmHg6HIIJJGBJ777 $hqqq!tn =AbnT!!!Q$Z!!!Q$8899	'7	#	# 4hY&~bmHg6HIIJJ GBJ777 $hqqq!tn<@bnT!!!Q$Z!!!Q$889
  	N2>$qqq!t*d111a4jAA8AAAqD>RR	
 	

 2333 w///H Or   c                    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   rr   z Cartesian points must be (n, 3)!T)r-           r   )r"   r#   r9   rk   r+   r2   abs	TOL_MERGETzerosr%   column_stackarctan2arccos)	cartesianr1   r0   xyz	sphericals          r   vector_to_sphericalr     s     irz:::IIw'' =;<<<)666KD%%(D		!"fGAq!#i..!,BJ???I
1a(8(8")A,,'GHHIer   c                 n   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   rq   z%spherical coordinates must be (n, 2)!)	r"   r#   r9   rk   r+   r   sincosr   )r   thetaphistctspcps          r   spherical_to_vectorr     s     irz:::IIw'' B@AAAJE3VE]]BF5MMBVC[["&++B?BGR"Wb1222r   c                 f   t          | t          j                  r]|                     d          } t          j        | | f          }|                    d          dd                             d          }|S ddl}|                    |           \  }}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   rq   r   N)	rP   r"   ndarrayr)   r   	itertoolsteenextri   )iterablestackedpairsr   r<   r=   s         r   pairwiser     s    2 (BJ'' ##B''/8X"677##AbD)11':: ==""DAqGGGq!99r   z1np.linalg.multi_dot not available, using fallbackc                     t          j        |           } | d                                         }| dd         D ]}t          j        ||          }|S )z
        Compute the dot product of two or more arrays in a single function call.
        In most versions of numpy this is included, this slower function is
        provided for backwards compatibility with ancient versions of numpy.
        r   r   N)r"   r#   r*   r(   )arraysresultr^   s      r   	multi_dotr      sU     v&&!! 	' 	'AVFA&&FFr   c                 x    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#   r(   r&   r;   s     r   diagonal_dotr   -  s9    ` 	aA 6!a%#+,,,r   c                 t    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"   r'   r(   r&   )datas    r   row_normr   c  s1    . 726$'A3A#677888r   c                 z   t          j        | t           j                  } | j        }|dk    rd}nt	          |          dk    rt          d          |d         dk    r8t          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#   r9   r&   r%   r+   r   r   )points	return_2Dr&   is_2Ds       r   stack_3Dr   }  s    & ]6444FLE}}	Uq3444	qQ&"(3v;;*?*?!@AA	qQ;<<< u}Mr   c                    t          j        | t           j                  } t          |           dk    rt	          d          t          j        |t           j                  }|j        dk    r t          j        || j        d                   }d t          | j        |          D             }t          j	        t          j
        |ddi                              | j        d         d	          j        }|S )
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!ra   r   c                 6    g | ]\  }}t          j        |d |iS )step)r"   arange)r]   r=   ss      r   
<listcomp>zgrid_arange.<locals>.<listcomp>  s+    KKKtq!RY***KKKr   indexingijr    )r"   r#   r9   r%   r+   r&   tileri   r   vstackmeshgridr)   )boundsr   grid_elementsgrids       r   grid_aranger     s     ]6444F
6{{a8999 =RZ000DzRwtV\!_--KKs68T7J7JKKKM
	"+}<t<<==	a"	%	%	
 	
 Kr   c                    t          j        | t           j                  } t          |           dk    rt	          d          t          j        |t           j                  }|j        dk    r t          j        || j        d                   }d t          | j	        |          D             }t          j
        t          j        |ddi                              | j        d         d	          j	        }|S )
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   ra   r   c                 6    g | ]\  }}t          j        |d |iS )num)r"   linspace)r]   r=   cs      r   r   z!grid_linspace.<locals>.<listcomp>  s+    MMM1R[!+++MMMr   r   r   r    )r"   r#   r9   r%   r+   int64r&   r   ri   r   r   r   r)   )r   countr   r   s       r   grid_linspacer     s     ]6444F
6{{a8999M%rx000E{bv|A//MMFHe8L8LMMMM
	"+}<t<<==	a"	%	%	
 	
 Kr   c                 ~    t          j        t                    }| D ] \  }}||                             |           !|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defaultdictrn   append)r   r   kvs       r   
multi_dictr     sG      $T**F  1q	Mr   c                 H    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     r   tolistr     s     Z&&FMr   c                     |                                  }|                     d          }|                     |           t          |t                    }|D ]}|rt          |          }n|}|dk    r dS  dS )zo
    Returns True if file has non-ASCII characters (> 0x7F, or 127)
    Should work in both Python 2 and 3
    i      TF)tellr@   seekrP   rQ   ord)file_objstartfbytesis_strfbytecodes         r   is_binary_filer     s    
 MMOOE]]4  FMM%$$F   	u::DDD#::44 5r   c                     |                                  }|                     dd           |                                  }|                     |           ||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       r   distance_to_endr     sV      }}MM!Q==??LMM"###..HOr   c                     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
    N   )r   intr"   log10clip)decimal
min_digitsdigitss      r   decimal_to_digitsr   2  sH     RXg&&''((FR00v;;r   Tc                    |g d}t          j        |           t          j        dd          }|r-	 ddlm}  |dddd	d
dddd          }n# t
          $ r Y nw xY w|t          j                    }|                    |           |                    |            |5t          t           j
        j        j                                                  }|                    t          j        d                     dt          j        d          _        |D ]Xj        j        dk    st'          fd|D                       r.                    |                               |            Yt+          j        dd           dS )a  
    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
    N)TerminalIPythonApp
PYREADLINEpyembreeshapely
matplotlibparsozD[%(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   Loggerc              3   L   K   | ]}j                             |          V  d S r[   )r   
startswith)r]   r=   loggers     r   r_   z attach_to_log.<locals>.<genexpr>  sD       8
 8
*+FK""1%%8
 8
 8
 8
 8
 8
r      )	precisionsuppress)loggingcaptureWarnings	Formattercolorlogr   ImportErrorStreamHandlersetFormattersetLevelrd   r   manager
loggerDictvaluesadd	getLoggerdisabledrJ   rK   any
addHandlerr"   set_printoptions)	levelhandlerloggerscolorscapture_warnings	blacklist	formatterr   r  s	           @r   attach_to_logr  F  s	   4 
 
 
	 ,--- !N I  	111111((J ##'" %   II  	 	 	D	 ')) ###U gn,7>>@@AAKK!-00111 .2Gj!!*   $00C 8
 8
 8
 8
/88
 8
 8
 5
 5
0 '""" !d333333s   A 
AAc                 H   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                              |          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    rq   Nr   )r"   r#   r%   rm   rT   r   r)   )indicesr&   s     r   stack_linesr"    s    N mG$$G
7||qx||	WQZ	 	  S__%?GCRCL'!""+677??FFFr   c                 h   t          j        d | D                       }t          j        dt          j        |          dd                   }g }t	          ||          D ]1\  }}t          |          dk    r|                    ||z              2t          |           }t          |          }||fS )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
    c                 ,    g | ]}t          |          S ra   r%   r]   r^   s     r   r   z append_faces.<locals>.<listcomp>  s    :::SVV:::r   r   Nr    )r"   rm   r   cumsumri   r%   vstack_empty)vertices_seq	faces_seqvertices_lenface_offset	new_facesoffsetfacesverticess           r   append_facesr1    s    * 8::\:::;;L)Ary66ss;<<KI[)44 ) )u::??((((L))H##EU?r    
   {}c                    t          j        |           } t          |          }t          |          }t          |          }t          |          }t	          | j                  dk    r"t          dt          | j                            | j        j        t          d          |	                    d          }| j        j
        dv r||z   }nW| j        j
        dk    r-|                    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        |                     d          d|f                              d          } |j        | d|          }	|	S )aI  
    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 bad.

    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{r^   ufr5  {:.f}dtype %s not convertible!r   r!   r    )r"   r#   r   rQ   r%   r&   r+   r   namesr   kindreplacer   r   r)   format)
rm   	col_delim	row_delimr   value_formatrepeats
format_strend_junkshaped	formatteds
             r   array_to_stringrK     s   8 M%  E[[FIIII|$$L 5;!;S=M=M
 
 	

 {$WXXX   %%G{:%%!I-

		S	 	 !))$F0Cd0JKKiW

4ek6FGGG 9~~H
5;1ek!n$
 13y>>/ 12Y>
y>> #e**J WU]]7++a\::BB2FFF "
!6*:XI:6Ir   c                 b    t          j                    t          |          }t          |          }t          |          }t          |          }t	           j                  dk    r"t          dt           j                             j        j        t          d          |	                    d          dk    rt          d|          d} j        j        D ]} |         j        j
        }t	           |         j                  dk    r |         j        d         nd}|d	v r|                    d
d          |z   }	nH|dk    r-|                    d
dt          |          z   dz             |z   }	nt          d j                  |||	z  z  }|dt	          |                    |z   }|t	                     z  }t	                     t          j         fd j        j        D                                           d          }
 |j        |
 dt	          |                    }|S )aQ  
    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 conversionsare
    surprisingly bad.

    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   r7  Nz4array is not structured, use array_to_string insteadr8  zNvalue_format %s is invalid, repeating unstructured array values is unsupported r   r9  r5  z{:0.0f}r;  r<  r=  r>  c                 J    g | ]}|                              d f           S )r    )r)   )r]   r   rm   r   s     r   r   z.structured_array_to_string.<locals>.<listcomp>  s/    BBB1q		5"+	&	&BBBr   r    )r"   r#   r   rQ   r%   r&   r+   r   r?  r   r@  rA  hstackr)   rB  )rm   rC  rD  r   rE  rG  r   r@  element_row_lengthelement_format_str	flattenedrJ  r   s   `           @r   structured_array_to_stringrS  N  sW   > M%  E[[FIIII|$$L 5;!;S=M=M
 
 	

 { OPPP #""&
 
 	
 J! > >T{ %58t9J5K5Kq5P5PU4[.q11VW:!-!5!5dI!F!F!RS[[ $$T53v;;+>+EFFR  8%+FFF(+===

 -s9~~o-.:J#e**J JJE	BBBBB0ABBB gbkk 
 "
!9-.?Y.?@Ir   base64c                    t          j        |           } | j        }t          j        |           }|| j        }t          j        |          j        |d}|dv rdt          j        |                    |          	                                          }t          |d          r|                    d          }||d<   n3|dk    r| 	                    d	          |d<   nt          d
| d          |S )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
    N)r   r&   )rT  dict64decodeutf-8rT  binaryC)orderz	encoding z is not available!)r"   r#   r&   ravelr   rQ   rT  	b64encodeastypetobytesrC   rW  r+   )rm   r   encodingr&   flatencodedpackeds          r   array_to_encodedrd    s    * M%  EKE8E??D}+e<<G'''!$++e"4"4"<"<">">??68$$ 	,]]7++F"	X		!MMM44AXAAABBBNr   rX  c                     |                                  }|D ]`}t          |d          rN|                    |          }||k    r3| |         | |                    |          <   |                     |           a| 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'}
    rW  )keysrC   rW  pop)storer`  rf  keydecodeds        r   decode_keysrk    s{    . ::<<D  3!! 	jj**Gg~~.3Cjcjj**+		#Lr   #c                    || vr| S | z                        |          }|                     |          rd}n|d         }fd|D             }|z                       d |D                       z   }|                                }|S )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
    rM  r   c                 <    g | ]}|                     d           S r   )split)r]   r^   new_lines     r   r   z!comment_strip.<locals>.<listcomp>  s'    333qwwx##333r   c              3   ~   K   | ]8}t          |          d k    t          |d                    dk    .|d          V  9dS )r   r   Nr%  r&  s     r   r_   z comment_strip.<locals>.<genexpr>  sB      NNQ!AaD		A!NNr   )rp  r  joinrW   )textstarts_withrq  rp  leadremovedr   s     `    r   comment_striprx    s    & $ H_##K00E {## Qx 4333U333G 	
	
--NNgNNN
N
N	O  \\^^FMr   c                    t          | t                    s4t          |           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         |          }d| v r|                    | d                   }|S )au  
    Turn a dictionary with base64 encoded strings back into a numpy array.

    Parameters
    ------------
    encoded : dict
      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: numpy array
    z(Unable to extract numpy array from inputr   rT  rY  r   r&   )rP   rc   rT   r"   r#   r+   rk  r   
frombufferrT  	b64decoder)   )rb  as_arrayr   rm   s       r   encoded_to_arrayr}    s    $ gt$$ Iw 	I}W--HOGHHH'""GHWW%&&E7f.wx/@AA5II	W		gh/u==='gg.//Lr   c                      	 t          |t                    rt           fd|D                       S t           |           dS # t          $ r Y dS 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   8   K   | ]}t          |          V  d S r[   is_instance_namedr\   s     r   r_   z$is_instance_named.<locals>.<genexpr>V  s.      ??Q(a00??????r   TF)rP   rn   r  
type_namedr+   rM   s   ` r   r  r  C  st    "dD!! 	"????$??????sD!!!t   uus   /A A 
AAc                 0   t          j        t          | j        j                  g          }t          |          D ]'}|                    d |d         D                        (	 t          j        |          }n# t          $ r g }Y nw xY wd |D             S )z0
    Return the bases of the object passed.
    c                      g | ]}||j         S r[   )__base__r&  s     r   r   ztype_bases.<locals>.<listcomp>d  s    EEEQq}aj}}}r   r    c                 2    g | ]}t          |d           |S )rK   rB   r&  s     r   r   ztype_bases.<locals>.<listcomp>i  s'    777!: 6 67A777r   )
r   dequern   rJ   	__bases__ranger   r"   rO  
IndexError)rE   depthbasesr^   s       r   
type_basesr  ^  s     tCM$;<<=>>E5\\ G GEE%)EEEFFFF	%     77u7777s   %A: :B	B	c                     t          |          }| j        j        |k    r| j        S t          |           D ]}|j        |k    r|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
      Nnme of class

    Returns
    ----------
    class : Optional[Callable]
      Camed class, or None
    z Unable to extract class of name )rQ   rJ   rK   r  r+   )rE   r   bases      r   r  r  l  sk    $ t99D
}%%}3  =D  KKK !
7$>
?
??r   )ztrimesh.Trimeshztrimesh.path.Path2Dztrimesh.path.Path3Dc                    g }| :t          |           r|                    |            n|                    |            |:t          |          r|                    |           n|                    |           g }|D ]O}t          |d          r(|                    |                                           :|                    |           Pt          |          dk    r|d                                         S t          |          dk    rddlm}  |            S d |D             }d |D             }t          |          t          |          k    rddl	m
}  ||          S t          |          dk    rg S t          |d         d	          }	t          d
 |D             d |D                       \  }
}d}t          d |D                       r+t          d |D                       }|j        |j        k    sJ d}t          d |D                       r+t          d |D                       }|j        |
j        k    sJ 	 |d         j        
                    d |dd         D                       }nF# t"          $ r9}t$                              dt(           d           d}t(          r|Y d}~nd}~ww xY w |	|
||||d          S )aI  
    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 : trimesh.Trimesh
      Concatenated mesh
    NScener   r   Trimeshc                 2    g | ]}t          |d           |S r  r  r]   r;  s     r   r   zconcatenate.<locals>.<listcomp>  s(    BBBQ"3Ay"A"ABqBBBr   c                 2    g | ]}t          |d           |S )rI   r  r  s     r   r   zconcatenate.<locals>.<listcomp>  s(    ???Q"3Av">">?q???r   )concatenater  c                 @    g | ]}|j                                         S ra   )r0  r*   r]   ms     r   r   zconcatenate.<locals>.<listcomp>  s$    ,,,q		,,,r   c                 @    g | ]}|j                                         S ra   )r/  r*   r  s     r   r   zconcatenate.<locals>.<listcomp>  s"    .O.O.O!qw||~~.O.O.Or   c              3   (   K   | ]}d |j         v V  dS )face_normalsN_cacher  s     r   r_   zconcatenate.<locals>.<genexpr>  s)      
7
7!>QX%
7
7
7
7
7
7r   c                     g | ]	}|j         
S ra   )r  r  s     r   r   zconcatenate.<locals>.<listcomp>  s    $E$E$EQ^$E$E$Er   c              3   (   K   | ]}d |j         v V  dS )vertex_normalsNr  r  s     r   r_   zconcatenate.<locals>.<genexpr>  s*      
9
9Aqx'
9
9
9
9
9
9r   c                     g | ]	}|j         
S ra   )r  r  s     r   r   zconcatenate.<locals>.<listcomp>  s    &I&I&IAq'7&I&I&Ir   c                     g | ]	}|j         
S ra   )visualr  s     r   r   zconcatenate.<locals>.<listcomp>  s    /N/N/NQ/N/N/Nr   zfailed to combine visuals T)exc_infoF)r0  r/  r  r  r  process)rT   extendr   r  dumpr%   r*   r  r  	path.utilr  r  r1  r  r(  r&   r  BaseExceptionlogdebug_STRICT)r<   r=   ra  r  r^   r  is_meshis_pathconcatenate_pathtrimesh_typer0  r/  r  r  r  Es                   r   r  r    sQ   * D}q>> 	KKNNNNKKNNN}q>> 	KKNNNNKKNNND  Q(( 	KK!!!!KKNNNN
4yyA~~Aw||~~	Ta!!!!!!wyyBB$BBBG??$???G
7||c'll"">>>>>>(((
7||q	 gaj)44L #,,G,,,.O.Ow.O.O.O OHe
 L

7
7w
7
7
777 1#$E$EW$E$E$EFF!U[0000 N

9
9
9
9
999 6%&I&I&I&I&IJJ#x~5555"../N/N'!""+/N/N/NOO   		8w884	HHH 	G	 	 	 	 	 <!%   s   2I: :
J=/J88J=c                 J    t          |          }t          |          dk    rg S  j                            t          j                  } j                            t          j                  }g }g }	g }
g }t	          j        t          |                    }|D ]l}t	          j        |          }t          |          dk    r+|j	        j
        dk    r1|                                sP||                                |k     rkn|t          |          |k     r||         }t	          j        |                    d                    }t	          j        t          |                    ||<   |
                     j        |                    |                    ||                    |	                    ||                    	 |                     j                            |                     [# t&          $ r d}Y jw xY wt          |	          dk    rt	          j        g           S t+           d          |rd}	 t	          j        |          }|d                             |dd                   }n# t&          $ r Y nw xY wt/          |	|          \  }	} |	|t	          j        |
          |d          }|S |dgt          |	          z  } fd	t3          |	||
|          D             }|s|rd
 |D             }|rd t3          ||          D             S |S )a7  
    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 : bool
        Try to make submeshes watertight
    only_watertight : bool
        Only return submeshes which are watertight
    append : bool
        Return a single mesh which has the faces appended,
        if this flag is set, only_watertight is ignored

    Returns
    ---------
    if append : Trimesh object
    else        list of Trimesh objects
    r   r=   Nr    r  r   F)r0  r/  r  r  r  c                 j    g | ]/\  }}}} ||||t          j        j                  d           0S )F)r0  r/  r  r  metadatar  )r*   deepcopyr  )r]   r   r;  nr   meshr  s        r   r   zsubmesh.<locals>.<listcomp>P  sb     
 
 
 Aq!Q 	]4=11	
 	
 	

 
 
r   c                 f    g | ].}|                                 ot          |j                  d k    /S r
   )
fill_holesr%   r/  r&  s     r   r   zsubmesh.<locals>.<listcomp>_  s2    KKKqallnn:QW):KKKr   c                     g | ]	\  }}||
S ra   ra   )r]   r^   ws      r   r   zsubmesh.<locals>.<listcomp>b  s!    ;;;da;;;;r   )rn   r%   r/  viewr"   r   r0  r   r#   r   r@  r  r:   uniquer)   r   r  r  face_subsetr  rm   r  r  r1  r   ri   )r  faces_sequencerepaironly_watertight	min_facesr   original_facesoriginal_verticesr/  r0  normalsvisualsmaskindexcurrentr  r  appendedr   
watertightr  s   `                   @r   submeshr    sm   4 .))N
>a	 Z__RZ00N**2:66EHGG 9S*++,,D  e$$u::??;s""99;; $y)@)@"s5zzI'='= '7??2..// yV--Vt(/000T']###)&1222	NN4;22599:::: 	 	 	GGG	 8}}x|| dI..L 	hw''GQZ++GABBK88FF 	 	 	D	 'x77%<7++
 
 
 &3x==(
 
 
 
 
 hw@@
 
 
F  L& L LKFKKK
 <;;c&*55;;;;Ms$   -G55HH7I< <
J	J	c                 "   t          |           dk    rt          j        |          S t          |           |k     rBt          j        |          }|r| |t          |            d<   n| |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)r%   r"   r   r#   )r   r   rightpaddeds       r   zero_padr  g  s     4yyA~~x	TU		% 	'#'FCII:<<  "&F;SYY;}T"""r   c                 Z     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 ZdS )jsonify.<locals>.EdgeEncoderc                     t          |d          r|                                S t          |d          r|                                S t          j                            | |          S )Nr   	timestamp)rC   r   r  r   JSONEncoderdefault)selfrE   s     r   r  z$jsonify.<locals>.EdgeEncoder.default  s]     sH%% 'zz||#k** '}}&#++D#666r   N)rK   
__module____qualname__r  ra   r   r   EdgeEncoderr    s#        	7 	7 	7 	7 	7r   r  cls)r   r  dumps)rE   kwargsr  s      r   r   r     sN    $7 7 7 7 7d& 7 7 7 :c55{5f555r   c                    t          |t          j                  rt          j        | |j                  S t          | |j                  st          |          r| S t          |           r6t          |           dk    r#t          | d         |j                  r| d         S t          | t                    r@|j        j
        dk    r0|                     d          rddlm} |                    |           S |                    |           } | 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)rP   r"   r   r#   r   rJ   rU   rT   r%   rQ   rK   r  r   r  r   )itemliker  s      r   convert_liker    s   " $
## 5}T4444 $'' 74==  4 SYY!^^
47DN0S0S^Aw 	4	N#y00OOI&& 1
 	 yy >>$DKr   c           
         ddl }t          j        | t          j        d          } t	          | j                  dk    rE| j        d         dk    rt          d          |                     t	          |           d	f          } n2t	          | j                  dk    s| j        dk    rt          d
          | j        d         }|dz  dk    rt          d          t          |dz            }|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   r*   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"   rm   r9   r%   r&   r+   r)   sizer   r  PropertyIndexri   r   )r   r  r  r  s       r   bounds_treer    sK   " LLL XfBJT:::F
6<A<?a<===Vb 122	V\		a		6;!#3#3=>>> QIA!:;;;IM""I%%	%::J;BIc&kk""FTFS[[,@AAj    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!)rP   rQ   r   bytesr   r+   re   rK   )r  s    r   wrap_as_streamr    s`     $ ~~	D%	 	  t}}
T

+???
@
@@r   r   c                 <    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
    r   )
sigfig_int)r  sigfigas_int
multiplierroundeds        r   sigfig_roundr    s+    8 $FF33FJJ'GNr   c                 x   t          j        |                               d          } t          j        |t           j                                      d          }|j        | j        k    rt          d          t          j        t          |                     }t          j        |           t          k    }t          j
        t          j        t          j        | |                                       ||<   ||z
  dz   }| d|z  z                                                      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, int)
      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#   r)   r   r&   r+   r   r%   r   r$   floorr   roundr^  )r  r  exponentnonzeror  r  s         r   r  r  1  s    * ]6""**2..F]6222::2>>F|v|##7888xF$$HfVnnx'G"&*A*A!B!BCCHWF"Q&JJ'..0077AAF:r   c                    t          |                                          }t          | t                    rt	          |           } |                    d          r4t          j        |           fd                                D             S |                    d          rIddl	}| j
        dd         t	          |                    | d                                                    iS d	|d
d         v r;ddl}|                    | d          fd                                D             S t          d          )a  
    Given an open file object and a file type, return all components
    of the archive as open file objects in a dict.

    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}
    ri   c                 V    i | ]%}|t                              |                    &S ra   )r  r@   r]   r   archives     r   
<dictcomp>zdecompress.<locals>.<dictcomp>n  s/    XXXTnW\\$%7%788XXXr   bz2r   Nr)modetari)fileobjr	  c                 <    i | ]}|                     |          S ra   )extractfiler  s     r   r  zdecompress.<locals>.<dictcomp>w  s)    OOODg))$//OOOr   zUnsupported type passed!)rQ   lowerrP   r  r  rL   zipfileZipFilenamelistr  r   openr@   tarfilegetnamesr+   )r   	file_typer  r  r  s       @r   
decompressr  V  sG   $ I$$&&I(E"" ,!(++%   Y/(++XXXXWEUEUEWEWXXXX%   Y


crc"N388H383O3O3T3T3V3V$W$WXX	"##,,xc,::OOOOG<L<L<N<NOOOO
/
0
00r   c                    t                      }t          j        |fdt          j        d|5 }|                                 D ]?\  }}t          |d          r|                                }|                    ||           @	 ddd           n# 1 swxY w Y   |                    d           |                                }|S )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	  compressionr@   Nr   )	r   r  r  ZIP_DEFLATEDitemsrC   r@   writestrr   )infor  r   zipperr   r   
compresseds          r   compressr  {  s     yyH	
(<
 
@F
 
 (	**,, 	( 	(JD$tV$$ #yy{{OOD$''''		(( ( ( ( ( ( ( ( ( ( ( ( ( ( ( MM!Js   ABBBc                     t          |           } |ddg}|                     t          |                    r|D ]}|                     |          r|c S |                     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'
    Nztar.bz2ztar.gz.r    )rQ   rL   tuplerp  )	file_namespecialends      r   split_extensionr&    s    & IIh'%..))  	 	C!!#&& 


??3##r   c                 d   t          j        d | D                       }t          j        |           }t          j        t	          |          dz
  dft           j                  }t          d          D ]&}||d|z            |dt	          |          dz
  |f<   '|dd         |d<   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 )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
    c                 ,    g | ]}t          |          S ra   r%  r&  s     r   r   z,triangle_strips_to_faces.<locals>.<listcomp>  s    ///1A///r   r   r   r   Nr    Fr   r   T)r"   rm   r  r   r%   r   r  r'  ru   boolr   fliplr)stripslengthsblobtrir^   length_indexkeepflips           r   triangle_strips_to_facesr3    s   8 h/////00G >&!!D (CIIM1%RX
6
6
6C1XX 3 3"&q26z"2Oc$ii!mOQ233iCG 9W%%crc*L73s884(((D"D	"D	
d)C 9Q	'A+ 6 677L8L$D111D3|$$q()) D D?C\!_q <A#667!<<	#d)$$CIJr   c                 F    d | D             }t          j        |d          S )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
    c           
          g | ][}t          j        |d          t          j        t          |          dz
  t                    z  |dd         |dd         g          \S )r   r   r   r   r    N)r"   	transposeru   r%   r   )r]   fans     r   r   z*triangle_fans_to_faces.<locals>.<listcomp>   sn        	c!frws3xx!|3????QrTCPQPRPRGTUU  r   r   axis)r"   r  )fansr/  s     r   triangle_fans_to_facesr;    s7       E >%a((((r   c                     d | D             }t          |          dk    rt          j        |d                   S t          |          dk    rt          j        g           S t          j        |          S )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.
    c                 8    g | ]}t          |          d k    |S r   r%  r&  s     r   r   z vstack_empty.<locals>.<listcomp>  s#    ...q3q66A:::::r   r   r   )r%   r"   r#   rm   r   )tup	stackables     r   r(  r(    sk      /.C...I
9~~}Yq\***	Y1		x||9Yr   c                    dt          | dd          v }t          |t                    }t          |t                    }|r+|r)|                     |                    |                     nB|s+|r)|                     |                    |                     n|                     |           |                                  |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
    r=   r	  )getattrrP   rQ   r  rA   encoderW  flush)r   stuffr`  binary_filestring_stuffbinary_stuffs         r   write_encodedrH  "  s    ( 63777KeS))LeU++L | u||H--.... \ u||H--....uNNLr      c                 l    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UUIDrandomgetrandbitshex)lengths    r   	unique_idrS  D  s0     9+C00!<<<@&IIr   -q=c                    t          j        | t           j        d          } | j        dk    rt	          d          t           j                            |           }||k     rt          j        d          S | |z  } t          j        | d          | d         dg          }t           j                            |          }||k     rGt          j        | d	          | d         dg          }|t           j                            |          z  }n||z  }t          j        | |          }t          j        ||| gt           j        
          }t          rt          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                            |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	   r8  r   )r"   rm   r9   r&   r+   linalgr/   eyecrossr  r   r(   allclose)r   epsilonz_normr   x_normr   r   s          r   generate_basisr]  V  s   , 	"*4000Aw$0111Y^^AFvayy KA
1Q4%1s#$$AY^^AF HqteQqT3'((	RY^^A 	
V
AAXq!Qirz222F @vbfQll##d****vbfQll##d****vbfQll##d****{29>>&q>993?????Mr   atolc                 H    | |z
  }t          j        || k    ||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"   rv   )r<   r=   r^  diffs       r   isclosera    s)    , q5D>$$,t444r   c                 R    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`.
    )floatr"   ptp)r<   r=   r^  s      r   rY  rY    s#    & A$&&r   c                   <    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	S )
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.
    c                 R    i | _         |                                D ]
\  }}|| |<   d S r[   )_dictr  )r  r  r   r   s       r   __init__zFunctionRegistry.__init__  s9    
LLNN 	 	DAqDGG	 	r   c                     | j         |         S r[   rh  r  ri  s     r   rX   zFunctionRegistry.__getitem__  s    z#r   c                     t          |t                    st          d|          || v rt          d|           t	          |          st          d          || j        |<   d S )Nzkey must be a string, got z%Cannot set new value to existing key z'Cannot set value which is not callable.)rP   rQ   r+   KeyErrorcallablerh  )r  ri  values      r   __setitem__zFunctionRegistry.__setitem__  sy    #s## 	CA#AABBB$;;H3HHIII 	HFGGG
3r   c                 *    t          | j                  S r[   )iterrh  r  s    r   rY   zFunctionRegistry.__iter__  s    DJr   c                 *    t          | j                  S r[   )r%   rh  rt  s    r   __len__zFunctionRegistry.__len__  s    4:r   c                     || j         v S r[   rk  rl  s     r   __contains__zFunctionRegistry.__contains__  s    dj  r   c                      | |         |i |S r[   ra   )r  ri  argsr  s       r   __call__zFunctionRegistry.__call__  s    tCy$)&)))r   N)rK   r  r  __doc__ri  rX   rq  rY   rv  rx  r{  ra   r   r   rf  rf    s           
              ! ! !* * * * *r   rf  c           	      j   t          | d          s| S 	 |                     |          } n# t          $ r| ddl}|                    | dd                   }t
                              d                    ||d         |d                              |                     |d         d	          } Y nw xY w| S )
ap  
    Try to decode byte input as a string.

    Tries initial guess (UTF-8) then if that fails it
    uses chardet 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
    rW  r   Ni  z&Data not {}! Trying {} (confidence {})r`  
confidenceignoreerrors)rC   rW  UnicodeDecodeErrorchardetdetectr  r  rB  )rt  initialr  r  s       r   decode_textr    s    ( 4"" @{{7## @ @ @
 UdU,,		4;;
+VL-A 	
 	
 	
 {{6*-h{??@  Ks   * BB0/B0c                     t          | d          r*|                     dd                              d          S t          | d          r|                     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
    rB  asciir  r  rW  )rC   rB  rW  rQ   )rt  s    r   to_asciir  	  sn     tX 5{{78{44;;GDDD	x	 	  5{{78{444t99r   c                    t          j        | t           j                  } t          | j                  dk    s| j        d         dk    rt          d          t          j        | ddddgf         | dd         z  j         }|                                dz  }|d	k     }|s|S | dd         | dd         z   |	                    d
          z                      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!   r8  g      @)
r"   rm   r9   r%   r&   r+   subtractr   r:   r)   )r   
return_allproductareaccwcentroids         r   is_ccwr  0	  s    ( XfBJ///F
6<AaA!5!5;<<< kF3B3A;/&*<?@G;;==3D
*C 
 vabbz)W__W-E-EEJJPQJRRd
H hr   c                 "   | t          |           dk    r| |vr| S |d}n|                    | d          }| zt          |           dk    rg| dz   }|                     dd          }t          |          dk    r8|dk    r2	 t          |d                   }|d         dz   }n# t          $ r Y nw xY wnd}t          |dz   d|z   t          |          z             D ]&}|                    |          }||vr|||| <   |c S 't          d          )	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`
    Nr   z_{}_r   r   zgeometry_{}z Unable to establish unique name!)r%   getrsplitr   r  r  rB  r+   )r   containscounts	incrementr  rp  r^   checks           r   unique_namer  [	  sW   6 SZZ!^^X0E0E ~		JJua((	SZZ!^^EM	S!$$u::??yA~~  aMM	!!Hu,		     "	 9q=!i-#h--"?@@    ##  ! !uLLL ! 7
8
88s    B" "
B/.B/)FN)Fr[   )r2  r3  r4  r5  )NrT  )rX  )rl  r3  r  )TFNF)Tro  )rI  )rT  )r	   )kr|  abcrT  r   r*   r   r  rO  shutilr   timerM  r6   r  collections.abcr   ior   r   typingr   numpyr"   r  r  ABCnowwhichfinfor9   
resolutionr$   r   r  rW  	_IDENTITYflagsrQ   r*  r   r2   rc  r>   rF   rN   rR   rU   rT   rk   ro   r|   r   r   r   rV  r   AttributeErrorr  r   r   r   r   r   r   r   r   r   r   r   r   r  r"  r1  rK  rS  rd  rk  rx  r}  r  r  r  r  r  r  r   r  r  r  r  r  r  r  r&  r3  r;  r(  rH  rS  r]  ra  rY  rf  r  r  r  r  ra   r   r   <module>r     s  	 	 


           



     $ # # # # #                           g	""	g
i 28BJ*S0	
BF1BJ'''	$	 'S 'T ' ' ' '24 4 4 4n)u ) ) ) )"9 9 9"> > >& d        "D    .    @T Td Tt T T T Tn  0G G G GT  83 3 30& & &R 	#II   IIABBB
 
 
 
 
 3- 3- 3-l9 9 94% % % %P  >  <  ,  &  &  ( 3    * -_4 _4 _4 _4D.G .G .Gb$ $ $NK K K K^ BFV V V Vr& & & &R   B* * * *Z" " "J  68 8 8 8@ @ @8 
a a
JKa a a aJ V[y y y yx# # # #66 6 6@* * *Z( ( (VA A A*   D" " "J"1 "1 "1J  <$ $ $ $<7 7 7t) ) ),     6   DJ J J J$: : : :z5 5 5 5 5 54' ' ' ' ' ',&* &* &* &* &*w &* &* &*R) ) ) )X  0( ( ( (V>9 >9 >9 >9 >9 >9s   :D D'&D'