
    Tiѻ                     (   d Z ddlZddlZddlmZ ddlmZ ddlZddl	m
Z
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 dd
lmZ ddlm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( ddl)m*Z* ddl	m+Z+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1 ddl2m3Z3 ddlm4Z4 	 ddl	m5Z5 n"# e6$ rZ7 ej8        e7          Z5Y dZ7[7ndZ7[7ww xY w	 ddl	m9Z9 n"# e6$ rZ7 ej8        e7          Z9Y dZ7[7ndZ7[7ww xY w	 ddl:m;Z; n"# e6$ rZ7 ej8        e7          Z;Y dZ7[7ndZ7[7ww xY w	 ddl<m=Z= n"# e6$ rZ7 ej8        e7          Z=Y dZ7[7ndZ7[7ww xY w	 ddl>Z?n"# e6$ rZ7 ej8        e7          Z?Y dZ7[7ndZ7[7ww xY w G d dej@                  ZA G d deA          ZB G d deA          ZCdS )zm
path.py
-----------

A module designed to work with vector paths such as
those stored in a DXF or SVG file.
    N)deepcopy)sha256   )	boundscaching
comparisonconvex
exceptionsgroupingparentunitsutil)transformations)cache_decorator)log)tol_path)plane_transform)	plane_fit)
	ArrayLikeIterableListMappingNDArrayOptionalSelfTupleUnionfloat64to_rgba   )creationrastersegmentssimplify	traversal)Entityexport_pathconcatenate)repair)polygons)cKDTree)Polygonc                      e Zd ZdZ	 	 	 	 	 	 d=deeee         df         dee         dee	         de
dee         d	ee	         fd
Zd ZdefdZedee         fd            Zej        dee         fd            Zedee         fd            Zej        dee         fd            Zed             Zej        d             Zed             Zd Zed             Zed             Zed             Zed             Zed             Zed             Zedee         fd            Zedee         fd            Z d>d e!d!e
fd"Z"d# Z#d?d%Z$ed&             Z%ed'             Z&ed(             Z'ed)             Z(d*edefd+Z)d,e!ddfd-Z*d. Z+d@d/Z,d0 Z-d1 Z.d2 Z/d3 Z0ed4             Z1d5 Z2ede3ee                  fd6            Z4dAd7Z5de6fd8Z7d@d9ee!deee!df                  f         fd:Z8d; Z9d< Z:dS )BPathaq  
    A Path object consists of vertices and entities. Vertices
    are a simple (n, dimension) float array of points in space.

    Entities are a list of objects representing geometric
    primitives, such as Lines, Arcs, BSpline, etc. All entities
    reference vertices by index, so any transform applied to the
    simple vertex array is applied to the entity.
    NTentitiesverticesmetadataprocesscolorsvertex_attributesc                 P   || _         || _        || _        i | _        t	          |t
                    r| j                            |           i | _        || j                            |           t          j	        | j
                  | _        |r|                                  dS dS )a  
        Instantiate a path object.

        Parameters
        -----------
        entities : (m,) trimesh.path.entities.Entity
          Contains geometric entities
        vertices : (n, dimension) float
          The vertices referenced by entities
        metadata : dict
          Any metadata about the path
        process :  bool
          Run simple cleanup or not
        colors
          Set any per-entity colors.
        vertex_attributes
          Set any per-vertex array data.
        N)id_function)r2   r3   r6   r4   
isinstancedictupdater7   r   Cache__hash___cachemerge_vertices)selfr2   r3   r4   r5   r6   r7   kwargss           K/DATA/AppData/hermes/venv/lib/python3.11/site-packages/trimesh/path/path.py__init__zPath.__init__^   s    : !  h%% 	+M  ***!#("))*;<<< m>>> 	" !!!!!	" 	"    c                 v    dt          |           j         d| j        j         dt	          | j                   dS )zO
        Print a quick summary of the number of vertices and entities.
        z	<trimesh.z(vertices.shape=z, len(entities)=z)>)type__name__r3   shapelenr2   rA   s    rC   __repr__zPath.__repr__   sA     |4::.{{@S{{ehimivewew{{{{rE   returnc                     | j         5  |                                  |                                  |                                  ddd           n# 1 swxY w Y   | S )zM
        Apply basic cleaning functions to the Path object in-place.
        N)r?   r@   remove_duplicate_entitiesremove_unreferenced_verticesrK   s    rC   r5   zPath.process   s     [ 	0 	0!!!**,,,--///	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 s   =AAAc                     d | j         D             }t          d |D                       sdS t          j        d |D                       }d|j        d<   |S )z
        Colors are stored per-entity.

        Returns
        ------------
        colors : (len(entities), 4) uint8
          RGBA colors for each entity
        c                     g | ]	}|j         
S  )color.0es     rC   
<listcomp>zPath.colors.<locals>.<listcomp>   s    ...1qw...rE   c              3      K   | ]}|d uV  	d S NrS   rV   cs     rC   	<genexpr>zPath.colors.<locals>.<genexpr>   s&      ..Q1D=......rE   Nc                 ,    g | ]}t          |          S rS   r   r[   s     rC   rX   zPath.colors.<locals>.<listcomp>   s    333!71::333rE   F	WRITEABLE)r2   anynparrayflags)rA   rawr6   s      rC   r6   zPath.colors   sl     /......#..... 	433s33344$)[!rE   valuesc                     |dS t          |          }t          |          t          | j                  k    rt          d          t	          || j                  D ]\  }}||_        dS )z
        Set the color for every entity in the Path.

        Parameters
        ------------
        values : (len(entities), 4) uint8
          Color of each entity
        Nzcolors must be per-entity!)r    rJ   r2   
ValueErrorziprT   )rA   re   r6   r\   rW   s        rC   r6   zPath.colors   su     >Fv;;#dm,,,,9:::.. 	 	DAqAGG	 	rE   c                     | j         S rZ   )	_verticesrK   s    rC   r3   zPath.vertices   s
    ~rE   c                     |'t          j        g t          j                  | _        d S t          j        |t          j                  | _        d S )Ndtype)r   tracked_arrayra   r   rj   rA   re   s     rC   r3   zPath.vertices   sA    >$22RZHHHDNNN$26LLLDNNNrE   c                     | j         S )z
        The actual entities making up the path.

        Returns
        -----------
        entities : (n,) trimesh.path.entities.Entity
          Entities such as Line, Arc, or BSpline curves
        )	_entitiesrK   s    rC   r2   zPath.entities   s     ~rE   c                 r    |t          j        g           | _        d S t          j        |          | _        d S rZ   )ra   rb   rq   
asanyarrayro   s     rC   r2   zPath.entities   s/    >Xb\\DNNN]622DNNNrE   c                 $    d | j         D             S )z
        Get a list of the layer for every entity.

        Returns
        ---------
        layers : (len(entities), ) any
          Whatever is stored in each `entity.layer`
        c                     g | ]	}|j         
S rS   layerrU   s     rC   rX   zPath.layers.<locals>.<listcomp>   s    ///A///rE   )r2   rK   s    rC   layerszPath.layers   s     0/////rE   c                    t          | j                                                                      d          g}|                    d | j        D                        t          j        d                    |                    S )z
        A hash of the current vertices and entities.

        Returns
        ------------
        hash : long int
          Appended hashes
        zutf-8c              3   >   K   | ]}|                                 V  d S rZ   )_bytesrU   s     rC   r]   z Path.__hash__.<locals>.<genexpr>  s*      ::q

::::::rE   rE   )	hexr3   r>   encodeextendr2   r   	hash_fastjoin)rA   hashables     rC   r>   zPath.__hash__   sp     ..001188AAB::DM:::::: (!3!3444rE   c                     | j         dz                      t          j                  }t	          |                    d                                                    S )z
        Return a hash of the identifier.

        Returns
        ----------
        hashed : (64,) str
          SHA256 hash of the identifier vector.
        g     @C)order)
identifierastypera   int64r   tobytes	hexdigest)rA   as_ints     rC   identifier_hashzPath.identifier_hash  sH     /C'//99fnn3n//00::<<<rE   c                 D    t          j        | j        | j                  }|S )z
        Sequence of closed paths, encoded by entity index.

        Returns
        ---------
        paths : (n,) sequence of (*,) int
          Referencing self.entities
        )r&   closed_pathsr2   r3   )rA   pathss     rC   r   z
Path.paths  s     &t}dmDDrE   c                    t          | j                  dk    r&t          j        t          | j                            S t          j        t          j        t          | j                            t          j        | j                            S )z
        List of entities that aren't included in a closed path

        Returns
        ----------
        dangling : (n,) int
          Index of self.entities
        r   )rJ   r   ra   aranger2   	setdiff1dhstackrK   s    rC   danglingzPath.dangling  sc     tz??a9S//000|BIc$-&8&89929TZ;P;PQQQrE   c                 h    t          | j                            t          j                            }|S )z
        A KDTree object holding the vertices of the path.

        Returns
        ----------
        kdtree : scipy.spatial.cKDTree
          Object holding self.vertices
        )r.   r3   viewra   ndarray)rA   kdtrees     rC   r   zPath.kdtree.  s(     ++BJ7788rE   c                 b     t          t           fd j        D                                 }|S )z
        The total discretized length of every entity.

        Returns
        --------
        length : float
          Summed length of every entity
        c              3   L   K   | ]}|                     j                  V  d S rZ   )lengthr3   )rV   irA   s     rC   r]   zPath.length.<locals>.<genexpr>E  s1      JJq188DM22JJJJJJrE   )floatsumr2   )rA   r   s   ` rC   r   zPath.length;  s6     sJJJJDMJJJJJKKrE   c                 H    t          j         fd j        D             t           j                  }|                    d j        j        d         f          }t          j        |                    d          |                    d          gt           j                  S )z
        Return the axis aligned bounding box of the current path.

        Returns
        ----------
        bounds : (2, dimension) float
          AABB with (min, max) coordinates
        c                 D    g | ]}|                     j                  S rS   )r   r3   )rV   rW   rA   s     rC   rX   zPath.bounds.<locals>.<listcomp>W  s'    <<<QXXdm$$<<<rE   rl   r!   r   axis)	ra   rb   r2   r   reshaper3   rI   minmax)rA   pointss   ` rC   r   zPath.boundsH  s     <<<<dm<<<BJ
 
 

 T]%8%; <==x++VZZQZ-?-?@
SSSSrE   c                 8    | j                             d          S )z
        Return the centroid of axis aligned bounding box enclosing
        all entities of the path object.

        Returns
        -----------
        centroid : (d,) float
          Approximate centroid of the path
        r   r   )r   meanrK   s    rC   centroidzPath.centroid_  s     {Q'''rE   c                 8    t          j        | j        d          S )z
        The size of the axis aligned bounding box.

        Returns
        ---------
        extents : (dimension,) float
          Edge length of AABB
        r   r   )ra   ptpr   rK   s    rC   extentszPath.extentsl  s     vdk****rE   Fdesiredguessc                 4    t          j        | ||           dS )z
        Convert the units of the current drawing in place.

        Parameters
        -----------
        desired : str
          Unit system to convert to
        guess : bool
          If True will attempt to guess units
        )r   r   N)r   _convert_units)rA   r   r   s      rC   convert_unitszPath.convert_unitsx  s"     	T7%@@@@@@rE   c                     g }| j         D ])}|                    |                                           *t          j        |          | _        | j                                         dS )zb
        Turn every multi- segment entity into single segment
        entities in- place.
        N)r2   r~   explodera   rb   rq   r?   clear)rA   new_entitiesentitys      rC   r   zPath.explode  sf    
 m 	2 	2F 0 01111,//rE   皙?c                 2    t          j        | |           dS )z
        Find vertices without degree 2 and try to connect to
        other vertices. Operations are done in-place.

        Parameters
        ----------
        distance : float
          Connect vertices up to this distance
        )distanceN)r,   	fill_gaps)rA   r   s     rC   r   zPath.fill_gaps  s      	111111rE   c                     t          d t          | j                                                                                  D                       }|S )z
        Are all entities connected to other entities.

        Returns
        -----------
        closed : bool
          Every entity is connected at its ends
        c              3   "   K   | ]
}|d k    V  dS )r   NrS   rV   r   s     rC   r]   z!Path.is_closed.<locals>.<genexpr>  s&      OOQ!VOOOOOOrE   )allr;   vertex_graphdegreere   )rA   closeds     rC   	is_closedzPath.is_closed  sH     OOT$*;*B*B*D*D%E%E%L%L%N%NOOOOOrE   c                 2    t          | j                  dk    S )z
        Are any entities defined for the current path.

        Returns
        ----------
        empty : bool
          True if no entities are defined
        r   )rJ   r2   rK   s    rC   is_emptyzPath.is_empty  s     4=!!Q&&rE   c                 >    t          j        | j                  \  }}|S )z
        Return a networkx.Graph object for the entity connectivity

        graph : networkx.Graph
          Holds vertex indexes
        )r&   r   r2   )rA   graph_closeds      rC   r   zPath.vertex_graph  s     #/>>wrE   c                 L    t          j        d | j        D                       }|S )a  
        Get a list of which vertex indices are nodes,
        which are either endpoints or points where the
        entity makes a direction change.

        Returns
        --------------
        nodes : (n, 2) int
          Indexes of self.vertices which are nodes
        c                     g | ]	}|j         
S rS   )nodesrU   s     rC   rX   z%Path.vertex_nodes.<locals>.<listcomp>  s    :::q17:::rE   )ra   vstackr2   )rA   r   s     rC   vertex_nodeszPath.vertex_nodes  s)     	::DM:::;;rE   	transformc                    | j         j        d         }t          j        t          j                  j        |dz   |dz   fk    rt          d          t          j        t          j        |dz             z
                                            dk     r| S | j	        
                                 i }d| j	        j        v rfd| j        D             |d<   dD ]%}|| j	        j        v r| j	        j        |         ||<   &t          j        | j                   | _         | j	                                         | j	                                         | j	        j                            |           | S )	z
        Apply a transformation matrix to the current path in- place

        Parameters
        -----------
        transform : (d+1, d+1) float
          Homogeneous transformations for vertices
        r!   rl   ztransform is incorrect shape!g:0yE>discretec                 <    g | ]}t          j        |           S )matrix)tftransform_points)rV   dr   s     rC   rX   z(Path.apply_transform.<locals>.<listcomp>  s6     ! ! !=>#Ai888! ! !rE   )rootr   
path_validr   r   	enclosureenclosure_shellenclosure_directedr   )r3   rI   ra   rs   r   rg   abseyer   r?   verifycacher   r   r   r   id_setr<   )rA   r   	dimensionr   keys    `   rC   apply_transformzPath.apply_transform  s    M'*	M)2:>>>	?y1}i!m<<<<===VIy1} 5 5566::<<tCCK 	***! ! ! !BF-! ! !E*	
 	4 	4C dk'''![.s3c
 +DM)LLL 	  '''rE   namec                 (    | j         D ]	}||_        
dS )z
        Apply a layer name to every entity in the path.

        Parameters
        ------------
        name : str
          Apply layer name to every entity
        N)r2   rw   )rA   r   rW   s      rC   apply_layerzPath.apply_layer	  s(      	 	AAGG	 	rE   c                 p    t          j        | j        d                    }|                     |           |S )a  
        Translate so that every vertex is positive in the current
        mesh is positive.

        Returns
        -----------
        matrix : (dimension + 1, dimension + 1) float
          Homogeneous transformations that was applied
          to the current Path object.
        r   )r   translation_matrixr   r   rA   r   s     rC   rezerozPath.rezero  s5     &A77V$$$rE   c                 r   t          | j                  dk    rdS |(t          j        t          j        | j        z  d          }t          j        | j        |          \  }| j                 | _        fd| j	        
                                D             | _	        t          j        t          | j                  t                    }t          | j                  D ]\  }}t!          |          j        }|dv r||j                 |_        0t          j        ||j                           }|d	k    rIt          |          d
k    r|d         |d         k    r|dd         }n7t          |          dk     rd||<   n|dk    rt          |          d
k    rd||<   ||_        | j        |         | _        dS )a	  
        Merges vertices which are identical and replace references
        by altering `self.entities` and `self.vertices`

        Parameters
        --------------
        digits : None, or int
          How many digits to consider when merging vertices
        r   Nr!   )
min_digits)digitsc                 L    i | ] \  }}|t          j        |                   !S rS   )ra   rb   )rV   r   valueuniques      rC   
<dictcomp>z'Path.merge_vertices.<locals>.<dictcomp>8  s9     "
 "
 "
-7S%C%("
 "
 "
rE   rl   zBSpline Bezier TextLine   r   r   FArc)rJ   r3   r   decimal_to_digitstolmergescaler   unique_rowsr7   itemsra   onesr2   bool	enumeraterG   rH   r   
merge_runs)	rA   r   inverseentities_okindexr   kindr   r   s	           @rC   r@   zPath.merge_vertices'  s    t}""F>+CI
,BqQQQF".t}VLLLf-"
 "
 "
 "
;?;Q;W;W;Y;Y"
 "
 "
 gc$-00===&t}55 	# 	#ME6<<(D ,,, ' 6 ()?@@Fv~~v;;!##q	VBZ(?(?#BQBZFF[[1__).K&3v;;!#3#3%*E" #FMM k2rE   c                 >    | j         D ]}||j                 |_        dS )a4  
        Replace the vertex index references in every entity.

        Parameters
        ------------
        mask : (len(self.vertices), ) int
          Contains new vertex indexes

        Notes
        ------------
        entity.points in self.entities
          Replaced by mask[entity.points]
        N)r2   r   )rA   maskr   s      rC   replace_vertex_referenceszPath.replace_vertex_references[  s/     m 	0 	0F /FMM	0 	0rE   c                     t          |          dk    rdS t          j        t          | j                  t                    }d||<   | j        |         | _        dS )z
        Remove entities by index.

        Parameters
        -----------
        entity_ids : (n,) int
          Indexes of self.entities to remove
        r   Nrl   F)rJ   ra   r   r2   r   )rA   
entity_idskeeps      rC   remove_entitieszPath.remove_entitiesl  sT     z??aFws4=))666 Zd+rE   c                 ~    t          j        d | j        D             t                    }| j        |         | _        dS )z
        Remove entities which declare themselves invalid

        Notes
        ----------
        self.entities: shortened
        c                     g | ]	}|j         
S rS   )is_validr   s     rC   rX   z'Path.remove_invalid.<locals>.<listcomp>  s    <<<!*<<<rE   rl   N)ra   rb   r2   r   )rA   valids     rC   remove_invalidzPath.remove_invalid{  s;     <<dm<<<DIIIe,rE   c                     t          j        d | j        D                       }t          j        |          \  }}t          |          t          | j                  k    r| j        |         | _        dS dS )z
        Remove entities that are duplicated

        Notes
        -------
        self.entities: length same or shorter
        c                 ,    g | ]}t          |          S rS   )hashr   s     rC   rX   z2Path.remove_duplicate_entities.<locals>.<listcomp>  s    !A!A!Aa$q''!A!A!ArE   N)ra   rb   r2   r   r   rJ   )rA   entity_hashesr   _inverses       rC   rO   zPath.remove_duplicate_entities  sn     !A!A4=!A!A!ABB#/>>v;;#dm,,,, M&1DMMM -,rE   c                    t          | j                  dk    r t          j        g t          j                  S t          j        t          j        d | j        D                                           t          j                            S )z
        Which vertices are referenced by an entity.

        Returns
        -----------
        referenced_vertices: (n,) int, indexes of self.vertices
        r   rl   c                     g | ]	}|j         
S rS   )r   rU   s     rC   rX   z,Path.referenced_vertices.<locals>.<listcomp>  s    <<<AH<<<rE   )rJ   r2   ra   rb   r   r   r+   r   rK   s    rC   referenced_verticeszPath.referenced_vertices  sr     t}""8Bbh////yN<<dm<<<==DDRXNN
 
 	
rE   c                 .   | j         }t          j        t          | j                  t          j                  dz  }t          j        t          |          t          j                  ||<   |                     |           | j        |         | _        dS )z
        Removes all vertices which aren't used by an entity.

        Notes
        ---------
        self.vertices : reordered and shortened
        self.entities : entity.points references updated
        rl   r   )r  N)r  ra   r   rJ   r3   r   r   r  )rA   r   r  s      rC   rP   z!Path.remove_unreferenced_vertices  sz     )ws4=)):::R?yVBH===V&&D&111f-rE   c                 \    | j         | j        | j        fd| j        D             S )z
        A sequence of connected vertices in space, corresponding to
        self.paths.

        Returns
        ---------
        discrete : (len(self.paths),)
            A sequence of (m*, dimension) float
        c                 @    g | ]}t          j        |           S ))r2   r3   pathr   )r&   discretize_path)rV   r  r2   r   r3   s     rC   rX   z!Path.discrete.<locals>.<listcomp>  sF     
 
 
  %!H4u  
 
 
rE   )r   r2   r3   r   )rA   r2   r   r3   s    @@@rC   r   zPath.discrete  sU     
==
 
 
 
 
 
 
	
 
 
 	
rE   c                 "    t          | f||d|S )a}  
        Export the path to a file object or return data.

        Parameters
        ---------------
        file_obj : None, str, or file object
          File object or string to export to
        file_type : None or str
          Type of file: dxf, dict, svg

        Returns
        ---------------
        exported : bytes or str
          Exported as specified type
        )	file_typefile_objr(   )rA   r  r  rB   s       rC   exportzPath.export  s!      4R9xRR6RRRrE   c                 .    |                      d          S )Nr;   )r  )r  rK   s    rC   to_dictzPath.to_dict  s    {{V{,,,rE   rx   c                 r   i }t          | j                                                  D ]H}	 t          | j        |                   ||<   !# t          $ r t          j        d| d           Y Ew xY w<t          t                    rhnt                    fd| j
        D             }n| j
        } t          |           t          |          t          | j                  |d          }|S i }	 t          | j        j                                                  }|D ]$}t          | j        j        |                   ||<   %nE# t          $ r t          j        d           Y n%t           $ r t          j        dd	           Y nw xY w||j        _        |j                                         |S )
a6  
        Get a copy of the current mesh

        Parameters
        ------------
        layers
          If passed an iterable of layer names which will
          only include those layers in the copy of the path.

        Returns
        ---------
        copied : Path object
          Copy of self
        zkey z changed during copyNc                 &    g | ]}|j         v |S rS   rv   )rV   rW   rx   s     rC   rX   zPath.copy.<locals>.<listcomp>  s%    FFFaAGv4E4E4E4E4ErE   Fr2   r3   r4   r5   zunable to copy cacheTexc_info)listr4   keysr   RuntimeErrorr   warningr:   strsetr2   rG   r3   r?   r   debugBaseExceptionerrorr   )	rA   rx   r4   r   r2   copiedr   r'  ks	    `       rC   copyz	Path.copy  s      **,,-- 	> 	>C> (s); < < > > ><3<<<=====> &#&& %  VFFFF4=FFFHH}H dh''dm,,	
 
 
 M	=)..0011D : :#DK$5a$899a: 	. 	. 	.I,----- 	= 	= 	=I,t<<<<<<	= $s*   A"A0/A0:AE F-FFc                 (    ddl m}  ||           }|S )z
        Get a scene object containing the current Path3D object.

        Returns
        --------
        scene: trimesh.scene.Scene object containing current path
        r   )Scene)scener3  )rA   r3  r4  s      rC   r4  z
Path.scene(  s(     	"!!!!!drE   c                 (    t          | |g          }|S )a  
        Concatenate two Path objects by appending vertices and
        reindexing point references.

        Parameters
        -----------
        other: Path object

        Returns
        -----------
        concat: Path object, appended from self and other
        r*   )rA   otherconcats      rC   __add__zPath.__add__5  s     dE]++rE   )NNNTNNF)r   rZ   NN);rH   
__module____qualname____doc__r   r   r   r'   r   r   r   rD   rL   r   r5   propertyr   r6   setterr   r3   r2   rx   r>   r   r   r   r   r   r   r   r   r   r*  r   r   r   r   r   r   r   r   r   r   r@   r  r  r  rO   r  rP   r   r   r  r;   r   r1  r4  r8  rS   rE   rC   r1   r1   S   sC         >B(,&*&*/31" 1"	8F#3T9:1" 9%1" 7#	1"
 1" #1" $G,1" 1" 1" 1"f| | |     )    X& ]Xi0    ]( ''*    X _Mx	2 M M M _M 	 	 X	 _3 3 _3 
0 
0 X
05 5 5  
= 
= _
= 
 
 _
 R R _R 
 
 _
 
 
 _
 T T _T, 
(''* 
( 
( 
( _
( 	+) 	+ 	+ 	+ X	+A AS A A A A A  
2 
2 
2 
2   X 	' 	' X	'   _   _4 4t 4 4 4 4l
 
 
 
 
 
  $23 23 23 23h0 0 0", , ,	- 	- 	-2 2 2 
 
 _
. . .$ 
$ww/0 
 
 
 _
.S S S S$- - - - -D D5dHU395E,F!FG D D D DL      rE   r1   c                       e Zd ZdZd Z	 	 	 ddee         dee         deded	e	e
         f         fd
Zede	e
         fd            Zed             Zd ZdS )Path3DH
    Hold multiple vector curves (lines, arcs, splines, etc) in 3D.
    c                 T    t          j        dt          d            | j        |i |S )zV
        DEPRECATED: replace `path.to_planar`->`path.to_2D), removal 1/1/2026
        zDDEPRECATED: replace `path.to_planar`->`path.to_2D), removal 1/1/2026r   )category
stacklevel)warningswarnDeprecationWarningto_2D)rA   argsrB   s      rC   	to_planarzPath3D.to_planarK  s?     	R'	
 	
 	
 	

 tz4*6***rE   NTrI  normalcheckrM   Path2Dc                 J   | j         }t          |          dk    r"t                      t          j        d          fS | j        j        d         }|dk    rt          j        d          }n|dk    rt          d| d          |t          | j        |                   \  }}|]t          j	        |t          j
        	                              d          }|t          j        t          j        ||                    z  }t          ||
          }t          j	        |t          j
        	          }|j        dk    rt          d          |dk    rwt          j        | j        |          }||         dddf         }	t          j        |	          t$          j        k    rd}
|rt          d          n6|	                                }
n!|dk    r| j                                        }d}
t          j                            |          }t          j        |
          t$          j        k    r,t          j        dd|
g          }t          j        ||          }t5          | j                  }||d<   t          t5          | j                  |ddddf         |d          }||fS )a  
        Check to see if current vectors are all coplanar.

        If they are, return a Path2D and a transform which will
        transform the 2D representation back into 3 dimensions

        Parameters
        -----------
        to_2D : (4, 4) float
          Homogeneous transformation matrix to apply,
          if not passed a plane will be fitted to vertices.
        normal : (3,) float or None
          Normal of direction of plane to use.
        check
          Raise a ValueError if points aren't coplanar.

        Returns
        -----------
        planar
          Current path transformed onto plane
        to_3D : (4, 4) float
          Homeogenous transformations to move planar
          back into the original 3D frame.
        r      r!   r   r   zvertices are `zD != 2D | 3D`!Nrl   )originrL  )rP  rP  zunable to create transform!g        zpoints are not flat!to_3DFr#  )r  rJ   rN  ra   r   r3   rI   rg   r   rb   r   r   signdotr   r   r   r   r   planarr   r1  linalginvr   r   r   r4   r2   )rA   rI  rL  rM  
referenceddimr   NflatheightsheightrR  adjustr4   rU  s                  rC   rI  zPath3D.to_2DV  s   > -
z??a88RVAYY&& m!!$ !88F1IIEEAXXAcAAABBB =T]:677DAq!&
;;;CCAFFRWRVAv..///#1Q777E bj111;&  :;;;!88&t}e<<D:&qqq!t,Gvg++ =$%;<<<= !AXX=%%''DF 	e$$ 6&>>CJ&&*Aq&>::FF5&))E DM**! dm,,!!!RaR%[	
 
 
 u}rE   c                 h    t          j        t          j        | j                  | j        gf          S )z=
        Return a simple identifier for the 3D path.
        )ra   r+   r   identifier_simpleconvex_hullr   rK   s    rC   r   zPath3D.identifier  s2    
 ~)$*:;;dk]K
 
 	
rE   c                 J    t          j        | j        | j                           S )z
        Return a convex hull of the 3D path.

        Returns
        --------
        hull : trimesh.Trimesh
          A mesh of the convex hull of the 3D path.
        )r	   ra  r3   r  rK   s    rC   ra  zPath3D.convex_hull  s     !$-0H"IJJJrE   c                 D    |                                  } |j        di |S )z1
        Show the current Path3D object.
        rS   )r4  show)rA   rB   r4  s      rC   rd  zPath3D.show  s)     

uz##F###rE   )NNT)rH   r;  r<  r=  rK  r   r   r   r   r   r   rI  r   r   ra  rd  rS   rE   rC   rA  rA  F  s         	+ 	+ 	+ &*&*	j j	"j #j 	j
 
x))	*j j j jX 
GG, 
 
 
 _
 	K 	K _	K$ $ $ $ $rE   rA  c                      e Zd ZdZd"dZd Zd Zed             Zed#d            Z		 d$d
Z
d Zed             Zd%dZedefd            Zedefd            Zed             Zd Zd Zd&dZd'dZd Zd(dZd Zd)dZd*dZed             Zed             Zedeej                  fd            Z!ed             Z"ed              Z#ed!             Z$d	S )+rN  rB  Tc                 t    | j         r|                     d|           dS |                     d|           dS )zB
        Plot the current Path2D object using matplotlib.
        T)rd  annotationsN)r   plot_discreteplot_entities)rA   rg  s     rC   rd  zPath2D.show  sM     > 	CDkBBBBBDkBBBBBrE   c                 >    | j         }|                     |           |S )z
        Transform the current path so that its OBB is axis aligned
        and OBB center is at the origin.

        Returns
        -----------
        obb : (3, 3) float
          Homogeneous transformation matrix
        )obbr   r   s     rC   	apply_obbzPath2D.apply_obb  s$     V$$$rE   c                     t          j        d          }|ddddfxx         |z  cc<   |                     |          S )z
        Apply a 2D scale to the current Path2D.

        Parameters
        -------------
        scale : float or (2,) float
          Scale to apply in-place.
        r   Nr   )ra   r   r   )rA   r   r   s      rC   apply_scalezPath2D.apply_scale  sG     rr2A2v%##F+++rE   c                 Z    t          j        | j        | j                           d         }|S )z
        Get a transform that centers and aligns the OBB of the
        referenced vertices with the XY axis.

        Returns
        -----------
        obb : (3, 3) float
          Homogeneous transformation matrix
        r   )r   oriented_bounds_2Dr3   r  r   s     rC   rk  z
Path2D.obb  s)     *4=9Q+RSSTUVrE   rM   c                 t   ddl m} ddlm} | j        | j                 g}|                    | j                   t          j	        |          }t          |          dk     rt                      S 	  ||          }n4# t          $ r' t          j        dd           t                      cY S w xY wt          j        t          |j                            }t          j        t          |j                            ||j        <   ||j                 }|j        |j                 }t          d
i  |||	          S )z
        Return a convex hull of the 2D path.

        Returns
        --------
        hull
          A convex hull of included vertices from this path.
        r   )
ConvexHullr!   edges_to_pathr   zFailed to construct convex hullTr$  edgesr3   rS   )scipy.spatialrr  exchange.miscrt  r3   r  r~   r   ra   r   rJ   rN  r-  r   r,  r   r   	simplices)rA   rr  rt  
candidateshullremaprv  r3   s           rC   ra  zPath2D.convex_hull  sO    	-,,,,,000000 mD$<=>
 	$-(((Yz**
 z??Q88O	:j))DD 	 	 	 I7$GGGG88OOO		 	#dk**++!yT]););<<dm dn%;t}-FFEHEEEFFFs   0A< <.B-,B-Nc                 :    t          j        | |||||          }|S )al  
        Rasterize a Path2D object into a boolean image ("mode 1").

        Parameters
        ------------
        pitch : float or (2,) float
          Length(s) in model space of pixel edges
        origin : (2,) float
          Origin position in model space
        resolution : (2,) int
          Resolution in pixel space
        fill : bool
          If True will return closed regions as filled
        width : int
          If not None will draw outline this wide (pixels)

        Returns
        ------------
        raster : PIL.Image object, mode 1
          Rasterized version of closed regions.
        )pitchrQ  
resolutionfillwidth)r#   	rasterize)rA   r~  rQ  r  r  r  rB   images           rC   r  zPath2D.rasterizeD  s4    0  !
 
 
 rE   c                    | j         }t          |          dk    rt          j        g           }nOt          |          dk    rt	          j        |d         fdi}n!t          j        fd|D                       }|S )a}  
        Use rejection sampling to generate random points inside a
        polygon.

        Parameters
        -----------
        count : int
          Number of points to return
          If there are multiple bodies, there will
          be up to count * bodies points returned
        factor : float
          How many points to test per loop
          IE, count * factor
        max_iter : int,
          Maximum number of intersection loops
          to run, total points sampled is
          count * factor * max_iter

        Returns
        -----------
        hit : (n, 2) float
          Random points inside polygon
        r   r!   countc                 8    g | ]}t          j        |fd iS )r  )r-   sample)rV   r   r  rB   s     rC   rX   z!Path2D.sample.<locals>.<listcomp>  s0    IIIq::%:6::IIIrE   )polygons_fullrJ   ra   rb   r-   r  r   vstack_empty)rA   r  rB   polysampless    ``  rC   r  zPath2D.samplef  s    2 !t99>>hrllGGYY!^^od1gEEUEfEEGG'IIIIIDIII G rE   c                 *    t          | j                  S )a   
        Returns a count of the number of unconnected polygons that
        may contain other curves but aren't contained themselves.

        Returns
        ---------
        body_count : int
          Number of unconnected independent polygons.
        )rJ   r   rK   s    rC   
body_countzPath2D.body_count  s     49~~rE   c                 h   |d| j         v r| j         d         }t          j        t          | j                  t          j        t          | j                            f          }|t          j        ||          }t          t          | j
                  |t          | j                             }|S )ax  
        Convert 2D path to 3D path on the XY plane.

        Parameters
        -------------
        transform : (4, 4) float
          If passed, will transform vertices.
          If not passed and 'to_3D' is in self.metadata
          that transform will be used.

        Returns
        -----------
        path_3D : Path3D
          3D version of current path
        NrR  )r2   r3   r4   )r4   ra   column_stackr   r3   zerosrJ   r   r   rA  r2   )rA   r   r3   path_3Ds       rC   rR  zPath2D.to_3D  s    " DM!9!9g.I ?dm$$bhs4=/A/A&B&BC
 
  *8Y??Hdm,,dm,,
 
 

 rE   c                 4    t          j        | j                  S )a  
        Cycles in the vertex graph, as shapely.geometry.Polygons.
        These are polygon objects for every closed circuit, with no notion
        of whether a polygon is a hole or an area. Every polygon in this
        list will have an exterior, but NO interiors.

        Returns
        ---------
        polygons_closed : (n,) list of shapely.geometry.Polygon objects
        )r-   paths_to_polygonsr   rK   s    rC   polygons_closedzPath2D.polygons_closed  s     )$-888rE   c                 R   dgt          | j                  z  }| j        }| j        t	          | j                  D ]j\  }}fd||                                         D             }d |D             }|         j        }t          j        t          ||                    ||<   k|S )a"  
        A list of shapely.geometry.Polygon objects with interiors created
        by checking which closed polygons enclose which other polygons.

        Returns
        ---------
        full : (len(self.root),) shapely.geometry.Polygon
            Polygons containing interiors
        Nc                      g | ]
}|         S rS   rS   )rV   childr   s     rC   rX   z(Path2D.polygons_full.<locals>.<listcomp>  s    JJJ%uJJJrE   c                 \    g | ])}t          j        |j        j                  d d d         *S )Nr   )ra   rb   exteriorcoords)rV   ps     rC   rX   z(Path2D.polygons_full.<locals>.<listcomp>  s2    III1RXaj/0026IIIrE   )shellholes)
rJ   r   r   r  r   r'  r  r-   repair_invalidr/   )	rA   fullr   r   r   childrenr  r  r   s	           @rC   r  zPath2D.polygons_full  s     vDI&+	% !++ 		Q 		QGAt KJJJ9T?3G3G3I3IJJJHIIIIIE4L)E-gE.O.O.OPPDGGrE   c                 \    t          t          d | j        D                                 }|S )z
        Return the area of the polygons interior.

        Returns
        ---------
        area : float
          Total area of polygons minus interiors
        c              3   $   K   | ]}|j         V  d S rZ   )arear   s     rC   r]   zPath2D.area.<locals>.<genexpr>  s$      <<A<<<<<<rE   )r   r   r  )rA   r  s     rC   r  zPath2D.area  s0     S<<);<<<<<==rE   c                 x    ddl m fd| j        D             }t          |          dk    r|d         S |S )a  
        Extrude the current 2D path into a 3D mesh.

        Parameters
        ----------
        height: float, how far to extrude the profile
        kwargs: passed directly to meshpy.triangle.build:
                triangle.build(mesh_info,
                               verbose=False,
                               refinement_func=None,
                               attributes=False,
                               volume_constraints=True,
                               max_volume=None,
                               allow_boundary_steiner=True,
                               allow_volume_steiner=True,
                               quality_meshing=True,
                               generate_edges=None,
                               generate_faces=False,
                               min_angle=None)
        Returns
        --------
        mesh: trimesh object representing extruded polygon
        r   )	Extrusionc                 &    g | ]} d|d S ))polygonr]  rS   rS   )rV   r   r  r]  rB   s     rC   rX   z"Path2D.extrude.<locals>.<listcomp>  s=     
 
 
>?II9a99&99
 
 
rE   r!   r   )
primitivesr  r  rJ   )rA   r]  rB   resultr  s    `` @rC   extrudezPath2D.extrude  sp    0 	+*****
 
 
 
 
 
CGCU
 
 
 v;;!!9rE   c                     ddl m} g }g }| j        D ]8} ||fi |\  }}|                    |           |                    |           9t	          j        ||          S )ax  
        Create a region- aware triangulation of the 2D path.

        Parameters
        -------------
        **kwargs : dict
          Passed to `trimesh.creation.triangulate_polygon`

        Returns
        -------------
        vertices : (n, 2) float
          2D vertices of triangulation
        faces : (n, 3) int
          Indexes of vertices for triangles
        r   )triangulate_polygon)r"   r  r  appendr   append_faces)rA   rB   r  v_seqf_seqr  vfs           rC   triangulatezPath2D.triangulate  s      	322222  ) 	 	G&&w99&99DAqLLOOOLLOOOO ...rE   c                     
| j         dz  ddlm fd| j        D             }fd|D             }t	          |          }|S )a  
        Find the approximate medial axis based
        on a voronoi diagram of evenly spaced points on the
        boundary of the polygon.

        Parameters
        ----------
        resolution : None or float
          Distance between each sample on the polygon boundary
        clip : None, or (2,) float
          Min, max number of samples

        Returns
        ----------
        medial : Path2D object
          Contains only medial axis of Path
        Ng     @@r!   rs  c                 <    g | ]}t          j        |          S rS   )r-   medial_axis)rV   r   clipr  s     rC   rX   z&Path2D.medial_axis.<locals>.<listcomp>O  s5     
 
 
:;H J55
 
 
rE   c           
      D    g | ]\  }}t          di  ||           S )ru  rS   )rN  )rV   rW   r  rt  s      rC   rX   z&Path2D.medial_axis.<locals>.<listcomp>S  s:    VVVDAq6??MMA>>>??VVVrE   )r   rx  rt  r  r+   )rA   r  r  	edge_vertmedialsmedialrt  s    ``   @rC   r  zPath2D.medial_axis6  s    $ f,J 	100000
 
 
 
 
?C?Q
 
 
	 WVVVIVVV W%%rE   Fc                 &   t          | j                  dk    r't          j        t          | j                            }n't          t          j        | j        |                    }|rt          j	        |          S t          j
        ||g          S )a  
        Given an index of self.paths find other paths which
        overlap with that path.

        Parameters
        -----------
        path_id : int
          Index of self.paths
        include_self : bool
          Should the result include path_id or not

        Returns
        -----------
        path_ids :  (n, ) int
          Indexes of self.paths that overlap input path_id
        r!   )rJ   r   ra   r   r  r&  nxnode_connected_componentr   rb   r   )rA   path_idinclude_selfpath_idss       rC   connected_pathszPath2D.connected_pathsZ  s{    " ty>>QyT%9!:!:;;HHB7PPQQH 	&8H%%%|Hwi000rE   c                 &    t          j        | fi |S )z
        Return a version of the current path with colinear segments
        merged, and circles entities replacing segmented circular paths.

        Returns
        ---------
        simplified : Path2D object
        )r%   simplify_basicrA   rB   s     rC   r%   zPath2D.simplifys  s     &t66v666rE   -C6*?c                 0    t          j        | ||          S )aS  
        Convert paths into b-splines.

        Parameters
        -----------
        smooth : float
          How much the spline should smooth the curve
        verbose : bool
          Print detailed log messages

        Returns
        ------------
        simplified : Path2D
          Discrete curves replaced with splines
        )smoothverbose)r%   simplify_spline)rA   r  r  s      rC   r  zPath2D.simplify_spline~  s      'VWMMMMrE   c                 *    t          j        |           S )z
        If the current Path2D consists of n 'root' curves,
        split them into a list of n Path2D objects

        Returns
        ----------
        split:  (n,) list of Path2D objects
          Each connected region and interiors
        )r&   splitr  s     rC   r  zPath2D.split  s     t$$$rE   c                 z   ddl m} |                                }|                    dd           t	          | j                  D ](\  }}ddg|| j        v          } |j        |j        d|i )|r5| j	        D ]-}t          |d          s|                    | j                   .|r|                                 |S )	z5
        Plot the closed curves of the path.
        r   Nequaldatalimgr0  rT   plot)matplotlib.pyplotpyplotgca
set_aspectr   r   r   r  Tr2   hasattrr3   rd  )	rA   rd  rg  pltr   r   r   rT   rW   s	            rC   rh  zPath2D.plot_discrete  s     	('''''wwyy+++"4=11 	. 	.IAv#JqDI~.EDIvx-u---- 	&] & &q&)) t}%%%% 	HHJJJrE   c           
      v   ddl m} |                                }|                    dd           ddddddd	ddd
ddddddddddddddd}| j        D ]}|r+t          |d          r|                    | j                   /|                    | j                  }|j	        j
        t          t          |j                            z   }	||	                                         }
|||
d<   nt          |d          r
|j        |
d<    |j        |j        i |
 |r|                                 dS dS )aR  
        Plot the entities of the path with no notion of topology.

        Parameters
        ------------
        show : bool
          Open a window immediately or not
        annotations : bool
          Call an entities custom plot function.
        color : str
          Override entity colors and make them all this color.
        r   Nr  r  r  r!   )rT   	linewidthyrbr0  m)Line0Line1Arc0Arc1Bezier0Bezier1BSpline0BSpline1r  rT   )r  r  r  r  r2   r  r  r3   r   	__class__rH   r*  intr   r1  rT   r  rd  )rA   rd  rg  rT   r  r   eformatr   r   e_keyfmts              rC   ri  zPath2D.plot_entities  s    	(''''' wwyy+++  #33"33!22!22!$155!$155"%A66"%A66	
 	
 m 	* 	*F wvv66 DM***t}55H$-C4F4F0G0GGE%.%%''C $G)) ,%|GDIxz)S)))) 	HHJJJJJ	 	rE   c                    t           j        | j        }t          |          dk    r | j        d                   S t          |          dk    rt	          j        d          S t	          j        fd|D             d          S )z
        A unique identifier for the path.

        Returns
        ---------
        identifier : (5,) float
          Unique identifier
        r!   r      c                 &    g | ]} |          S rS   rS   )rV   r  hashers     rC   rX   z%Path2D.identifier.<locals>.<listcomp>  s!    111Qvvayy111rE   r   )r-   r   r  rJ   ra   r  r   )rA   targetr  s     @rC   r   zPath2D.identifier  s     $#v;;!6$,Q/000[[A8A;;v1111&111::::rE   c                 V    t          j        d | j        D             t                    S )z
        Returns
        ----------
        path_valid : (n,) bool
          Indexes of self.paths self.polygons_closed
          which are valid polygons.
        c                     g | ]}|d uS rZ   rS   r   s     rC   rX   z%Path2D.path_valid.<locals>.<listcomp>   s    EEE1$EEErE   rl   )ra   rb   r  r   rK   s    rC   r   zPath2D.path_valid  s+     xEE0DEEETRRRRrE   c                 *    | j         }| j        d         S )z
        Which indexes of self.paths/self.polygons_closed
        are root curves, also known as 'shell' or 'exterior.

        Returns
        ---------
        root : (n,) int
          List of indexes
        r   )r   r?   )rA   populates     rC   r   zPath2D.root  s     *{6""rE   c                 v    | j         5  | j                                        }ddd           n# 1 swxY w Y   |S )z
        Undirected graph object of polygon enclosure.

        Returns
        -----------
        enclosure : networkx.Graph
          Enclosure graph of self.polygons by index.
        N)r?   r   to_undirected)rA   
undirecteds     rC   r   zPath2D.enclosure  s     [ 	A 	A0>>@@J	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	As   .22c                 R    t          j        | j                  \  }}|| j        d<   |S )z
        Directed graph of polygon enclosure.

        Returns
        ----------
        enclosure_directed : networkx.DiGraph
          Directed graph: child nodes are fully
          contained by their parent node.
        r   )r-   enclosure_treer  r?   )rA   r   r   s      rC   r   zPath2D.enclosure_directed  s-     #1$2FGGi"FrE   c                 R      fd j         D             }t          j        |          S )z
        A dictionary of path indexes which are 'shell' paths, and values
        of 'hole' paths.

        Returns
        ----------
        corresponding : dict
          {index of self.paths of shell : [indexes of holes]}
        c                 B    g | ]}|                     |d           fS )F)r  )r  )rV   r  rA   s     rC   rX   z*Path2D.enclosure_shell.<locals>.<listcomp>8  s1    UUUa!T))!%)@@AUUUrE   )r   collectionsOrderedDict)rA   pairss   ` rC   r   zPath2D.enclosure_shell-  s2     VUUU49UUU&u---rE   )T)rM   rN  )NNNTNrZ   r:  r9  )r  F)FT)FTN)%rH   r;  r<  r=  rd  rl  rn  r   rk  ra  r  r  r>  r  rR  r   r  r   r  r  r  r  r  r  r%   r  r  rh  ri  r   r   ra   r   r   r   r   r   rS   rE   rC   rN  rN    s        C C C C  , , ,   _ +G +G +G _+G\ JN       D# # #J 
 
 X
       D 9 9 9 9 _9 t    _> 
 
 _
  B/ / /<" " " "H1 1 1 12	7 	7 	7N N N N$
% 
% 
%   .0 0 0 0d ; ; X;" S S XS #gbh' # # # _#   _   _ . . _. . .rE   rN  )Dr=  r  rF  r1  r   hashlibr   numpyra    r   r   r   r	   r
   r   r   r   r   r   r   r   	constantsr   r   r   geometryr   r   r   typedr   r   r   r   r   r   r   r   r   r   visualr    r"   r#   r$   r%   r&   r2   r'   exchange.exportr)   r+   r,   r-  EExceptionWrapperr-   rw  r.   shapely.geometryr/   networkxr  Geometryr1   rA  rN  rS   rE   rC   <module>r     s                        
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 % $ $ $ $ $ % % % % % %       ' ' ' ' ' ' & & & & & &                                                       ( ( ( ( ( (      
, , , ,(Z(++FFFFFF,. . . .*z*1--HHHHHH.-%%%%%%% - - -)j)!,,GGGGGG--((((((( - - -)j)!,,GGGGGG-( ( ( (	$	$Q	'	'BBBBBB(p p p p p6? p p pfV$ V$ V$ V$ V$T V$ V$ V$r[	. [	. [	. [	. [	.T [	. [	. [	. [	. [	.sx   B B: B55B:>C C$
CC$(C/ /D4D		DD D8D33D8<E E EE 