
    vjc                        d dl mZmZ d dlZddlmZ ddlmZmZm	Z	m
Z
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  ed	e
      Z G d de       Z! G d de!      Z" G d de!      Z# G d de!      Z$ G d de$      Z% G d de$      Z& G d de$      Z' G d de!      Z( G d de!e      Z) G d de)      Z* G d d e)      Z+ G d! d"e+      Z, G d# d$e%e+      Z- G d% d&e)      Z. G d' d(e)      Z/ G d) d*e!      Z0 G d+ d,e0      Z1 G d- d.e0      Z2 G d/ d0e0      Z3 G d1 d2e!      Z4d3 Z5 e5       Z6 G d4 d5e!      Z7d6 Z8 e8e6      Z9 G d7 d8e!      Z:y)9    )abstractmethodABCN   )Vector)ShapeProtocolShape1DProtocolFaceProtocolgeom_LUT_EDGEgeom_LUT_FACE)
pyparsing_commonLiteralWordnumsOptionalCombineone_ofGroupinfix_notationopAssoc)reduce)IterableListSequenceTypeVarcastShape)boundc                   D    e Zd ZdZdee   dee   fdZd Zd Z	d Z
d Zy	)
Selectorzd
    Filters a list of objects.

    Filters must provide a single method that filters objects.
    
objectListreturnc                     t        |      S )z
        Filter the provided list.

        The default implementation returns the original list unfiltered.

        :param objectList: list to filter
        :type objectList: list of OCCT primitives
        :return: filtered list
        )listselfr    s     ?/DATA/.local/lib/python3.12/site-packages/cadquery/selectors.pyfilterzSelector.filter$   s     J    c                     t        | |      S N)AndSelectorr%   others     r&   __and__zSelector.__and__0       4''r(   c                     t        | |      S r*   )SumSelectorr,   s     r&   __add__zSelector.__add__3   r/   r(   c                     t        | |      S r*   )SubtractSelectorr,   s     r&   __sub__zSelector.__sub__6   s    e,,r(   c                     t        |       S r*   )InverseSelector)r%   s    r&   __neg__zSelector.__neg__9   s    t$$r(   N)__name__
__module____qualname____doc__r   r   r   r'   r.   r2   r5   r8    r(   r&   r   r      s6    
 % 
 T%[ 
 ((-%r(   r   c                   (    e Zd ZdZd Zdee   fdZy)NearestToPointSelectora  
    Selects object nearest the provided point.

    If the object is a vertex or point, the distance
    is used. For other kinds of shapes, the center of mass
    is used to to compute which is closest.

    Applicability: All Types of Shapes

    Example::

       CQ(aCube).vertices(NearestToPointSelector((0, 1, 0)))

    returns the vertex of the unit cube closest to the point x=0,y=1,z=0

    c                     || _         y r*   )pnt)r%   rA   s     r&   __init__zNearestToPointSelector.__init__O   s	    r(   r    c                 *      fd}t        ||      gS )Nc                 v    | j                         j                  t        j                         j                  S r*   )Centersubr   rA   Length)tShaper%   s    r&   distz+NearestToPointSelector.filter.<locals>.distS   s)    ==?&&vtxx'89@@@r(   key)min)r%   r    rI   s   `  r&   r'   zNearestToPointSelector.filterR   s    	A JD)**r(   Nr9   r:   r;   r<   rB   r   r   r'   r=   r(   r&   r?   r?   =   s    "+% +r(   r?   c                   *    e Zd ZdZddZdee   fdZy)BoxSelectora^  
    Selects objects inside the 3D box defined by 2 points.

    If `boundingbox` is True only the objects that have their bounding
    box inside the given box is selected. Otherwise only center point
    of the object is tested.

    Applicability: all types of shapes

    Example::

        CQ(aCube).edges(BoxSelector((0, 1, 0), (1, 2, 1)))
    c                 F    t        | | _        t        | | _        || _        y r*   )r   p0p1test_boundingbox)r%   point0point1boundingboxs       r&   rB   zBoxSelector.__init__h   s     &/&/ +r(   r    c                 $  	
 g }| j                   j                         \  
| j                  j                         \  		
fd}|D ]  }| j                  r|j	                         } |t        |j                  |j                  |j                              sQ |t        |j                  |j                  |j                              s|j                  |        ||j                               s|j                  |        |S )Nc                     | j                   k  | j                   k  z  xr@ | j                  k  | j                  k  z  xr | j                  k  | j                  k  z  S r*   )xyz)px0x1y0y1z0z1s    r&   isInsideBoxz'BoxSelector.filter.<locals>.isInsideBoxs   s\     ##(qssRx( .ccBh1338,.ccBh1338,r(   )rQ   toTuplerR   rS   BoundingBoxr   xminyminzminxmaxymaxzmaxappendrE   )r%   r    resultrc   obbr]   r^   r_   r`   ra   rb   s         @@@@@@r&   r'   zBoxSelector.filterm   s    WW__&
BWW__&
B	 	 A$$]]_vbggrww@Ak277BGGRWW5G MM!$qxxz*MM!$  r(   N)FrM   r=   r(   r&   rO   rO   Y   s    ,
% r(   rO   c                   N    e Zd ZdZddedefdZdedefdZde	e
   dee
   fd	Zy
)BaseDirSelectorzV
    A selector that handles selection on the basis of a single direction vector.
    vector	tolerancec                      || _         || _        y r*   )	directionrs   )r%   rr   rs   s      r&   rB   zBaseDirSelector.__init__   s    "r(   vecr!   c                      y)zMTest a specified vector. Subclasses override to provide other implementationsTr=   r%   rv   s     r&   testzBaseDirSelector.test   s    r(   r    c                 v   g }|D ]  }|j                         dk(  r3|j                         dk(  r t        t        |      j	                  d      }nF|j                         dk(  r2|j                         dk(  rt        t
        |      j                         }n| j                  |      s|j                  |        |S )z
        There are lots of kinds of filters, but for planes they are always
        based on the normal of the plane, and for edges on the tangent vector
        along the edge
        FacePLANENEdgeLINE)		ShapeTypegeomTyper   r	   normalAtr   	tangentAtry   rl   )r%   r    rrn   test_vectors        r&   r'   zBaseDirSelector.filter   s     A{{}&1::<7+B #<3<<TB&(QZZ\V-C"?A6@@Byy%  r(   N)-C6?)r9   r:   r;   r<   r   floatrB   boolry   r   r   r   r'   r=   r(   r&   rq   rq      sH    #v #% # 4 % T%[ r(   rq   c                        e Zd ZdZdedefdZy)ParallelDirSelectora  
    Selects objects parallel with the provided direction.

    Applicability:
        Linear Edges
        Planar Faces

    Use the string syntax shortcut \|(X|Y|Z) if you want to select based on a cardinal direction.

    Example::

        CQ(aCube).faces(ParallelDirSelector((0, 0, 1)))

    selects faces with the normal parallel to the z direction, and is equivalent to::

        CQ(aCube).faces("|Z")
    rv   r!   c                 f    | j                   j                  |      j                  | j                  k  S r*   )ru   crossrG   rs   rx   s     r&   ry   zParallelDirSelector.test   s&    ~~##C(//$..@@r(   Nr9   r:   r;   r<   r   r   ry   r=   r(   r&   r   r      s    $A A4 Ar(   r   c                        e Zd ZdZdedefdZy)DirectionSelectora  
    Selects objects aligned with the provided direction.

    Applicability:
        Linear Edges
        Planar Faces

    Use the string syntax shortcut +/-(X|Y|Z) if you want to select based on a cardinal direction.

    Example::

        CQ(aCube).faces(DirectionSelector((0, 0, 1)))

    selects faces with the normal in the z direction, and is equivalent to::

        CQ(aCube).faces("+Z")
    rv   r!   c                 R    | j                   j                  |      | j                  k  S r*   )ru   getAnglers   rx   s     r&   ry   zDirectionSelector.test   s     ~~&&s+dnn<<r(   Nr   r=   r(   r&   r   r      s    $= =4 =r(   r   c                        e Zd ZdZdedefdZy)PerpendicularDirSelectora  
    Selects objects perpendicular with the provided direction.

    Applicability:
        Linear Edges
        Planar Faces

    Use the string syntax shortcut #(X|Y|Z) if you want to select based on a
    cardinal direction.

    Example::

        CQ(aCube).faces(PerpendicularDirSelector((0, 0, 1)))

    selects faces with the normal perpendicular to the z direction, and is equivalent to::

        CQ(aCube).faces("#Z")
    rv   r!   c                     t        | j                  j                  |      t        j                  dz  z
        | j
                  k  S )N   )absru   r   mathpirs   rx   s     r&   ry   zPerpendicularDirSelector.test   s2    4>>**3/$''A+=>OOr(   Nr   r=   r(   r&   r   r      s    &P P4 Pr(   r   c                   8    e Zd ZdZdefdZdee   dee   fdZ	y)TypeSelectora  
    Selects objects having the prescribed geometry type.

    Applicability:
        Faces: PLANE, CYLINDER, CONE, SPHERE, TORUS, BEZIER, BSPLINE, REVOLUTION, EXTRUSION, OFFSET, OTHER
        Edges: LINE, CIRCLE, ELLIPSE, HYPERBOLA, PARABOLA, BEZIER, BSPLINE, OFFSET, OTHER

    You can use the string selector syntax. For example this::

        CQ(aCube).faces(TypeSelector("PLANE"))

    will select 6 faces, and is equivalent to::

        CQ(aCube).faces("%PLANE")

    
typeStringc                 .    |j                         | _        y r*   )upperr   )r%   r   s     r&   rB   zTypeSelector.__init__  s    $**,r(   r    r!   c                 v    g }|D ]1  }|j                         | j                  k(  s!|j                  |       3 |S r*   )r   r   rl   )r%   r    r   rn   s       r&   r'   zTypeSelector.filter  s5    Azz|t.  r(   N)
r9   r:   r;   r<   strrB   r   r   r   r'   r=   r(   r&   r   r      s.    "-3 -% T%[ r(   r   c                   ~    e Zd ZdZddededefdZdee	   de
e	   fdZed	e	defd
       Zdee	   de
e
e	      fdZy)_NthSelectorzj
    An abstract class that provides the methods to select the Nth object/objects of an ordered list.
    ndirectionMaxrs   c                 .    || _         || _        || _        y r*   )r   r   rs   )r%   r   r   rs   s       r&   rB   z_NthSelector.__init__  s    ("r(   
objectlistr!   c           	         t        |      dk(  rt        d      | j                  |      }| j                  s|j	                          	 || j
                     }|S # t        $ r% t        d| j
                   dt        |             w xY w)z|
        Return the nth object in the objectlist sorted by self.key and
        clustered if within self.tolerance.
        r   z/Can not return the Nth element of an empty listzAttempted to access index z of a list with length )len
ValueErrorclusterr   reverser   
IndexError)r%   r   	clusteredouts       r&   r'   z_NthSelector.filter  s     z?aNOOLL,	  	DFF#C 
  	,TVVH4KCPYNK[\ 	s   A .Bobjc                     t         )z
        Return the key for ordering. Can raise a ValueError if obj can not be
        used to create a key, which will result in obj being dropped by the
        clustering method.
        NotImplementedErrorr%   r   s     r&   rK   z_NthSelector.key3  s
     "!r(   c                 X   g }|D ]'  }	 | j                  |      }|j                  ||f       ) |j                  d        g g}|d   d   }|D ]I  \  }}t	        ||z
        | j
                  k  r|d   j                  |       6|j                  |g       |}K |S # t        $ r Y w xY w)zS
        Clusters the elements of objectlist if they are within tolerance.
        c                     | d   S )Nr   r=   )rY   s    r&   <lambda>z&_NthSelector.cluster.<locals>.<lambda>K  s    qtr(   rJ   r   )rK   r   rl   sortr   rs   )r%   r   key_and_objr   rK   r   starts          r&   r   z_NthSelector.cluster<  s     Chhsm Sz*  	^,D	Aq!#HC3;4>>1"$$S)  #' $   s   B	B)(B)NTr   )r9   r:   r;   r<   intr   r   rB   r   r   r   r'   r   rK   r   r=   r(   r&   r   r     s~    ## #T #U #
% T%[ , "u " " "(5/ d4;6G r(   r   c                        e Zd ZdZdedefdZy)RadiusNthSelectorz
    Select the object with the Nth radius.

    Applicability:
        All Edge and Wires.

    Will ignore any shape that can not be represented as a circle or an arc of
    a circle.
    r   r!   c                 x    |j                         dv rt        t        |      j                         S t	        d      )Nr}   Wirez%Can not get a radius from this object)r   r   r   radiusr   r   s     r&   rK   zRadiusNthSelector.keyb  s3    ==?..-4466DEEr(   Nr9   r:   r;   r<   r   r   rK   r=   r(   r&   r   r   W  s    Fu F Fr(   r   c            	       J     e Zd ZdZ	 	 d
dedededef fdZde	defd	Z
 xZS )CenterNthSelectorz
    Sorts objects into a list with order determined by the distance of their center projected onto the specified direction.

    Applicability:
        All Shapes.
    rr   r   r   rs   c                 6    t         |   |||       || _        y r*   )superrB   ru   )r%   rr   r   r   rs   	__class__s        r&   rB   zCenterNthSelector.__init__q  s     	L)4r(   r   r!   c                 T    |j                         j                  | j                        S r*   )rE   dotru   r   s     r&   rK   zCenterNthSelector.key{  s    zz|//r(   r   )r9   r:   r;   r<   r   r   r   r   rB   r   rK   __classcell__r   s   @r&   r   r   i  sN     "!     	 
  0u 0 0r(   r   c                   4     e Zd ZdZ	 ddededef fdZ xZS )DirectionMinMaxSelectoraP  
    Selects objects closest or farthest in the specified direction.

    Applicability:
        All object types. for a vertex, its point is used. for all other kinds
        of objects, the center of mass of the object is used.

    You can use the string shortcuts >(X|Y|Z) or <(X|Y|Z) if you want to select
    based on a cardinal direction.

    For example this::

        CQ(aCube).faces(DirectionMinMaxSelector((0, 0, 1), True))

    Means to select the face having the center of mass farthest in the positive
    z direction, and is the same as::

        CQ(aCube).faces(">Z")

    rr   r   rs   c                 ,    t         |   d|||       y )Nr   )r   rr   r   rs   )r   rB   )r%   rr   r   rs   r   s       r&   rB   z DirectionMinMaxSelector.__init__  s      	li 	 	
r(   r   )	r9   r:   r;   r<   r   r   r   rB   r   r   s   @r&   r   r     s1    , MS

,0
DI
 
r(   r   c            	       J    e Zd ZdZ	 	 ddedededefdZde	e
   dee
   fd	Zy
)DirectionNthSelectorz
    Filters for objects parallel (or normal) to the specified direction then returns the Nth one.

    Applicability:
        Linear Edges
        Planar Faces
    rr   r   r   rs   c                 b    t         j                  | ||       t        j                  | |||       y r*   )r   rB   r   )r%   rr   r   r   rs   s        r&   rB   zDirectionNthSelector.__init__  s*     	$$T69=dA|Y?r(   r   r!   c                 ^    t         j                  | |      }t        j                  | |      }|S r*   )r   r'   r   )r%   r   s     r&   r'   zDirectionNthSelector.filter  s,    (//jA
!((z:
r(   Nr   )r9   r:   r;   r<   r   r   r   r   rB   r   r   r   r'   r=   r(   r&   r   r     sZ     "!@@ @ 	@
 @% T%[ r(   r   c                        e Zd ZdZdedefdZy)LengthNthSelectorzh
    Select the object(s) with the Nth length

    Applicability:
        All Edge and Wire objects
    r   r!   c                     |j                         dv rt        t        |      j                         S t	        dt        |      j                         )Nr   z5LengthNthSelector supports only Edges and Wires, not )r   r   r   rG   r   typer9   r   s     r&   rK   zLengthNthSelector.key  sI    ==?..-4466GS	HZHZG[\ r(   Nr   r=   r(   r&   r   r     s    u  r(   r   c                        e Zd ZdZdedefdZy)AreaNthSelectora  
    Selects the object(s) with Nth area

    Applicability:
        - Faces, Shells, Solids - Shape.Area() is used to compute area
        - closed planar Wires - a temporary face is created to compute area

    Will ignore non-planar or non-closed wires.

    Among other things can be used to select one of
    the nested coplanar wires or faces.

    For example to create a fillet on a shank::

       result = (
           cq.Workplane("XY")
           .circle(5)
           .extrude(2)
           .circle(2)
           .extrude(10)
           .faces(">Z[-2]")
           .wires(AreaNthSelector(0))
           .fillet(2)
       )

    Or to create a lip on a case seam::

       result = (
           cq.Workplane("XY")
           .rect(20, 20)
           .extrude(10)
           .edges("|Z or <Z")
           .fillet(2)
           .faces(">Z")
           .shell(2)
           .faces(">Z")
           .wires(AreaNthSelector(-1))
           .toPending()
           .workplane()
           .offset2D(-1)
           .extrude(1)
           .faces(">Z[-2]")
           .wires(AreaNthSelector(0))
           .toPending()
           .workplane()
           .cutBlind(2)
       )
    r   r!   c                 d   |j                         dv r|j                         S |j                         dk(  r;	 ddlm}m} t        |j                  t        ||            j                               S t        dt        |      j                         # t        $ r}t        d| d      d }~ww xY w)N)r{   ShellSolidr   r   )r{   r   z"Can not compute area of the Wire: z4. AreaNthSelector supports only closed planar Wires.zCAreaNthSelector supports only Wires, Faces, Shells and Solids, not )r   Areacadquery.occ_impl.shapesr{   r   r   makeFromWiresr   	Exceptionr   r   r9   )r%   r   r{   r   exs        r&   rK   zAreaNthSelector.key  s    ==?8888:]]_&?4--d4o>CCEFF UVZ[^V_VhVhUij    8<pq s   9B 	B/B**B/Nr   r=   r(   r&   r   r     s    /bu  r(   r   c                   .    e Zd ZdZd Zdee   fdZd Zy)BinarySelectorz
    Base class for selectors that operates with two other
    selectors. Subclass must implement the :filterResults(): method.
    c                      || _         || _        y r*   )leftright)r%   r   r   s      r&   rB   zBinarySelector.__init__  s    	
r(   r    c                     | j                  | j                  j                  |      | j                  j                  |            S r*   )filterResultsr   r'   r   r$   s     r&   r'   zBinarySelector.filter  s8    !!IIZ($***;*;J*G
 	
r(   c                     t         r*   r   r%   r_leftr_rights      r&   r   zBinarySelector.filterResults  s    !!r(   N)	r9   r:   r;   r<   rB   r   r   r'   r   r=   r(   r&   r   r     s!    

% 

"r(   r   c                       e Zd ZdZd Zy)r+   zT
    Intersection selector. Returns objects that is selected by both selectors.
    c                 B    t        t        |      t        |      z        S r*   r#   setr   s      r&   r   zAndSelector.filterResults$  s    CK#g,.//r(   Nr9   r:   r;   r<   r   r=   r(   r&   r+   r+     s    0r(   r+   c                       e Zd ZdZd Zy)r1   zC
    Union selector. Returns the sum of two selectors results.
    c                 0    t        t        ||z               S r*   r   r   s      r&   r   zSumSelector.filterResults.  s    C()**r(   Nr   r=   r(   r&   r1   r1   )  s    +r(   r1   c                       e Zd ZdZd Zy)r4   za
    Difference selector. Subtract results of a selector from another
    selectors results.
    c                 B    t        t        |      t        |      z
        S r*   r   r   s      r&   r   zSubtractSelector.filterResults9  s    CK#g,.//r(   Nr   r=   r(   r&   r4   r4   3  s    
0r(   r4   c                   (    e Zd ZdZd Zdee   fdZy)r7   z
    Inverts the selection of given selector. In other words, selects
    all objects that is not selected by given selector.
    c                     || _         y r*   )selector)r%   r   s     r&   rB   zInverseSelector.__init__C  s	     r(   r    c                 \    t        t               | j                        j                  |      S r*   )r4   r   r   r'   r$   s     r&   r'   zInverseSelector.filterF  s     
DMM:AA*MMr(   NrM   r=   r(   r&   r7   r7   =  s    
!N% Nr(   r7   c            	         t        d      } t        d      t        d      z  }t        t              }t        t	        |      |z         }t        |t	        | t	        |      z         z         }t        d      }t        d      }t        d      }t        | |d      z   |z    |d      z   |z    |d	      z   |z   d
      }t        g d      }	 |	d       |d      z  }
t        t        t        j                               t        t        j                               z  d      }|j                  t        j                        }t        d      }t        ddg      }t        ddg      }t        t	        d      t        t              z         }t        d      j                         }t        d      j                         }| |d      z   |z   }t        g d      }t        g d      } |
d       |d       |d      z   z   |d       |
d      z   t	        |      z   z   |d        |
d      z   t	        |      z   z   |d!       |
d      z   z   |d"      z  S )#zC
    Define the simple string selector grammar using PyParsing
    .+-(),rY   rZ   r[   F)adjacent)XYZXYXZYZ
simple_dir
vector_dirT)caseless%><>><<[]index)|#r   r   frontbackr   r   topbottomonly_dirtype_opcq_typedir_opdircenter_nth_opother_op
named_view)r   r   r   r   r   r   r   r
   valuesr   set_parse_actionr   upcase_tokensr   suppress)pointplusminnumberintegerfloatnlbracketrbracketcommarr   r  ru   cqtyper  direction_opr  	ix_number
lsqbracket
rsqbracketr  r  r  s                        r&   _makeGrammarr1  K  sE    CLEclWS\)G$ZFhw'&01GWx0@(@AABF s|Hs|HCLE6#;&4u<vc{JXUF 9:J<(6,+??I M  "#c-*>*>*@&AADF $$%5%C%CDF clG 3*%L D$<(M hsmd4j01I&&(J&&(J7++j8E *+H KLJ 	*9y 11	3!Ie$44xF	H )Ie,<<xN	P J)E"22		4
 \
"	#r(   c                   4    e Zd ZdZd Zd Zd Zdee   fdZ	y)_SimpleStringSyntaxSelectorzg
    This is a private class that converts a parseResults object into a simple
    selector object
    c           
         t        ddd      t        ddd      t        ddd      t        ddd      t        ddd      t        ddd      d| _        t        ddd      dft        ddd      dft        ddd      dft        ddd      dft        ddd      dft        ddd      dfd| _        ddddd| _        t        d t
        t        d	| _        || _        | j                  |      | _
        y )
Nr   r   )r   r  r  r  r  r  TFr  )r
  r  r  r  c                     t        |        S r*   )r   )vs    r&   r   z6_SimpleStringSyntaxSelector.__init__.<locals>.<lambda>  s    ,aR0r(   )r   r   r  r  )r   axes
namedViewsoperatorMinMaxr   r   r   operatorparseResults_chooseSelector
mySelector)r%   r;  s     r&   rB   z$_SimpleStringSyntaxSelector.__init__  s    1a1a1aAq/Aq/Aq/
	 Q1ot,Aq!_e,Aq!_e,Q1ot,1aOT*aA.
 	
 #0)$	
 )..|<r(   c           	         d|v r| j                  |      }t        |      S d|v rt        |j                        S d|v rw| j                  |      }| j                  |j
                     }d|v r=t        |t        dj                  |j                  j                                     |      S t        ||      S d|v rx| j                  |      }| j                  |j                     }d|v r=t        |t        dj                  |j                  j                                     |      S t        |d|      S d|v r0| j                  |      } | j                  |j                     |      S | j                   |j"                     }t        | S )	z<
        Sets up the underlying filters accordingly
        r  r  r  r   r  r   r  )
_getVectorr   r   r  r9  r  r   r   joinr  asListr   r  r   r:  r  r8  r  )r%   prrv   minmaxargss        r&   r<  z+_SimpleStringSyntaxSelector._chooseSelector  s`    //"%C$S))"_

++^//"%C((3F"}+RWWRXX__%678&  /sF;;"//"%C(()9)9:F"}(c"''"((//:K2L.MvVV(b&992//"%C-4==-c22 ??2==1D*D11r(   c                     d|v rR|j                   }t        t        |j                        t        |j                        t        |j
                              S | j                  |j                     S )zA
        Translate parsed vector string into a CQ Vector
        r  )r  r   r   rY   rZ   r[   r7  r  )r%   rC  rv   s      r&   r@  z&_SimpleStringSyntaxSelector._getVector  sO     2--C%,ceeeCEElCC99R]]++r(   r    c                 8    | j                   j                  |      S )z~
        selects minimum, maximum, positive or negative values relative to a direction
        ``[+|-|<|>|] <X|Y|Z>``
        r=  r'   r$   s     r&   r'   z"_SimpleStringSyntaxSelector.filter  s    
 %%j11r(   N)
r9   r:   r;   r<   rB   r<  r@  r   r   r'   r=   r(   r&   r3  r3    s(    
$=L%2N,2% 2r(   r3  c           
      R   t        d      }t        d      }t        ddg      }t        d      }d }| j                  |       d }d }d	 }d
 }	t        | |dt        j
                  |f|dt        j
                  |f|dt        j
                  |f|dt        j                  |	fg      }
|
S )zx
    Define the complex string selector grammar using PyParsing (which supports
    logical operations and nesting)
    andorexcexceptnotc                     t        |       S r*   )r3  )ress    r&   atom_callbackz-_makeExpressionGrammar.<locals>.atom_callback  s    *3//r(   c                 T    | j                         d   d d d   }t        t        |      S Nr   r   )rB  r   r+   rP  itemss     r&   and_callbackz,_makeExpressionGrammar.<locals>.and_callback  '    

Q!$k5))r(   c                 T    | j                         d   d d d   }t        t        |      S rS  )rB  r   r1   rT  s     r&   or_callbackz+_makeExpressionGrammar.<locals>.or_callback
  rW  r(   c                 T    | j                         d   d d d   }t        t        |      S rS  )rB  r   r4   rT  s     r&   exc_callbackz,_makeExpressionGrammar.<locals>.exc_callback  s(    

Q!$&..r(   c                 D    | j                         d   d   }t        |      S )Nr   r   )rB  r7   )rP  r   s     r&   not_callbackz,_makeExpressionGrammar.<locals>.not_callback  s!    

Q"u%%r(   r   r   )r   r   r!  r   r   LEFTRIGHT)atomand_opor_opdelta_opnot_oprQ  rV  rY  r[  r]  exprs              r&   _makeExpressionGrammarrf    s     U^FDMEuh'(HU^F0 	-(*
*
/
&
 Ql3Aw||[1q',,5Q|4		
D Kr(   c                   (    e Zd ZdZd Zdee   fdZy)StringSyntaxSelectoray  
    Filter lists objects using a simple string syntax. All of the filters available in the string syntax
    are also available ( usually with more functionality ) through the creation of full-fledged
    selector objects. see :py:class:`Selector` and its subclasses

    Filtering works differently depending on the type of object list being filtered.

    :param selectorString: A two-part selector string, [selector][axis]

    :return: objects that match the specified selector

    ***Modifiers*** are ``('|','+','-','<','>','%')``

        :\|:
            parallel to ( same as :py:class:`ParallelDirSelector` ). Can return multiple objects.
        :#:
            perpendicular to (same as :py:class:`PerpendicularDirSelector` )
        :+:
            positive direction (same as :py:class:`DirectionSelector` )
        :-:
            negative direction (same as :py:class:`DirectionSelector`  )
        :>:
            maximize (same as :py:class:`DirectionMinMaxSelector` with directionMax=True)
        :<:
            minimize (same as :py:class:`DirectionMinMaxSelector` with directionMax=False )
        :%:
            curve/surface type (same as :py:class:`TypeSelector`)

    ***axisStrings*** are: ``X,Y,Z,XY,YZ,XZ`` or ``(x,y,z)`` which defines an arbitrary direction

    It is possible to combine simple selectors together using logical operations.
    The following operations are supported

        :and:
            Logical AND, e.g. >X and >Y
        :or:
            Logical OR, e.g. \|X or \|Y
        :not:
            Logical NOT, e.g. not #XY
        :exc(ept):
            Set difference (equivalent to AND NOT): \|X exc >Z

    Finally, it is also possible to use even more complex expressions with nesting
    and arbitrary number of terms, e.g.

        (not >X[0] and #XY) or >XY[0]

    Selectors are a complex topic: see :ref:`selector_reference` for more information
    c                 p    || _         t        j                  |d      }|j                         d   | _        y)zl
        Feed the input string through the parser and construct an relevant complex selector object
        T)	parse_allr   N)selectorString_expression_grammarparse_stringrB  r=  )r%   rk  parse_results      r&   rB   zStringSyntaxSelector.__init__\  s7     -*77RV7W&--/2r(   r    c                 8    | j                   j                  |      S )z`
        Filter give object list through th already constructed complex selector object
        rH  r$   s     r&   r'   zStringSyntaxSelector.filterd  s     %%j11r(   NrM   r=   r(   r&   rh  rh  )  s    0d32% 2r(   rh  );abcr   r   r   occ_impl.geomr   occ_impl.shape_protocolsr   r   r	   r
   r   	pyparsingr   r   r   r   r   r   r   r   r   r   	functoolsr   typingr   r   r   r   r   r   objectr   r?   rO   rq   r   r   r   r   r   r   r   r   r   r   r   r   r+   r1   r4   r7   r1  _grammarr3  rf  rl  rh  r=   r(   r&   <module>rx     s   #  !     : :}-%v %@+X +8.( .b#h #LA/ A.= =.P P08 :A8S AHF F$0 0,
/ 
>.0A 2 "Al AH"X "&0. 0+. +0~ 0Nh N<~ >b2( b2J1h -X6 ?28 ?2r(   