
    ^j                       d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
mZ ddlmZmZ ddlmZ ddlmZmZmZ ddlmZmZmZmZmZmZ dd	lmZ dd
lmZ ddl m!Z!m"Z"m#Z#m$Z$ ddl%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ ddl,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:  ejv                  d      jy                   ejz                                 ejv                  d      Z>dZ?dZ@de@z  ZAde@z  ZBde@z  ZCdeCz  ZDeCdz  ZEe$j                  eBeCz  e$j                  eBeDz  e$j~                  eBe?z  e$j                  eBe@z  e$j                  eBeAz  e$j                  diZFdZGdeGz  ZHdeGz  ZId ZJ edeeKe         ZLdDdZMi dg ddg ddg dddgddgd g dd!d"gd#dgd$dgd%d"gd&d"gd'g dd(g dd)g dd*dgd+dgd,g ddgg ddd"gdgd-ZN ed.d/0      ZO	  ed1e30      ZP	  G d2 d/e
eeP         ZQ	 dE	 	 	 dFd3ZR G d4 d5      ZS G d6 d7eS      ZT G d8 d9eS      ZU G d: d;eS      ZV G d< d=eS      ZW G d> d?      ZX ed@      ZY	 	 	 	 dGdAZZ eZeQj                        Z[ eZeQj                        Z\ eZeQj                        Z] eZeQj                        Z^ eZeQj                        Z_ eZeQj                        Z` eZeQj                        Za eZeQj                        Zb eZeQj                        Zc eZeQj                        ZddHdBZee>j                  dC        eee)j                        e)_g         eee)j                        e)_h        y)Ia  
build123d Common

name: build_common.py
by:   Gumyr
date: July 12th 2022

desc:
    This is a Python code defining a class hierarchy for building CAD
    models. The code defines an abstract base class Builder with three
    concrete subclasses BuildLine, BuildPart, and BuildSketch in separate
    modules.

    The Builder class has several methods for adding and retrieving
    geometric shapes such as vertices, edges, faces, and solids. It also
    has a method _add_to_pending for adding shapes to a pending list that
    will be integrated into the final model later. The class has a
    _get_context method for retrieving the current Builder instance and a
    validate_inputs method for validating input shapes.

    The code also defines a validate_inputs function that takes a Builder
    instance and validates the input shapes.

license:

    Copyright 2022 Gumyr

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    )annotationsN)ABCabstractmethod)CallableIterable)product)cospisqrt)AnyGenericTypeTypeVarcastoverload)Standard_ConstructionError)Self)AlignModeSelectUnit)AxisLocationPlaneVector
VectorLiketo_align_offset)CompoundCurveEdgeFaceJointPartShape	ShapeListSketchSolidVertexWire	new_edgestuplify	build123dgMbP?   
   i  gffffff9@   gXzY|@c                J    t        | t              xr t        d | D              S )z$Identify points as tuples of numbersc              3  H   K   | ]  }t        |t        t        f        y wN)
isinstanceintfloat).0items     O/opt/ringagent/.cad-venv/lib/python3.12/site-packages/build123d/build_common.py	<genexpr>z_is_point.<locals>.<genexpr>   s       *+/
4#u&*s    ")r3   tupleall)objs    r8   	_is_pointr=      s*    c5! c *36* '     Tc                     t               }| D ]V  }t        |t        t        t        t
        f      r#t        |      s|j                  t        |        F|j                  |       X |S )zNConvert a sequence of object potentially containing iterables into a flat list)
r%   r3   listr:   filtersetr=   extendflatten_sequenceappend)r<   	flat_listr7   s      r8   rE   rE      s_     !*I # dT5&#67	$-t45T"# r>   add)	BuildPartBuildSketch	BuildLinebounding_boxchamferdraftrI   extrudefillet
full_roundrJ   loftmake_brake_formed	make_face	make_hullmirroroffsetprojectproject_workplanerevolvescale)sectionsplitsweepthickenBBuilder)boundShapeTc                     e Zd ZU dZ ej
                  d      Zded<   d ZdZ	e
j                  d	 	 	 d'dZeed(d              Zej                   ed)d	              Zed*d
       Zed+d       Zd,dZd Zd Zeddd-d       Ze	 	 d.	 	 	 	 	 	 	 d/d       Zdde
j                  d	 	 	 	 	 	 	 d0dZej6                  fd1dZej6                  fd2dZej6                  fd3dZej6                  fd4dZej6                  fd5dZ ej6                  fd6dZ!ej6                  fd7dZ"ej6                  fd8dZ#ej6                  fd9dZ$ej6                  fd:dZ%	 d;	 	 	 d<d Z&	 d;	 d=d!Z'd" Z(d,d#Z)d,d$Z*d,d%Z+d& Z,y)>ra   a  Builder

    Base class for the build123d Builders.

    Args:
        workplanes: sequence of Union[Face, Plane, Location]: set plane(s) to work on
        mode (Mode, optional): combination mode. Defaults to Mode.ADD.

    Attributes:
        mode (Mode): builder's combination mode
        workplanes (list[Plane]): active workplanes
        builder_parent (Builder): build to pass objects to on exit

    zBuilder._currentzcontextvars.ContextVar[Builder]_currentNonemodec                  || _         t        j                  |      }|r|nt        j                  g| _        d | _        t        j                         }|J |j                  J |j                  j                  | _
        d | _        d | _        t        g t        g t        g t         g i| _        d | _        g | _        d | _        g | _        y r2   )rh   WorkplaneList_convert_to_planesr   XY
workplanes
_reset_tokinspectcurrentframef_back_python_frameparent_framebuilder_parentr(   r    r!   r'   lastsworkplanes_contextexit_workplanes
obj_before
to_combine)selfrh   rm   planescurrent_frames        r8   __init__zBuilder.__init__   s    
 	11*=$*&
=A,,.(((##///*1188 .2"Bb$E2F
"&,.(,')r>   c                    t         )zObject to pass to parentNotImplementedErrorrz   s    r8   _objzBuilder._obj   s
     "!r>   c                    t         r2   r   )rz   values     r8   r   zBuilder._obj   s
     "!r>   c                f    | j                   r$| j                   j                         j                  S dS )z(Maximum size of object in all directions        )r   rL   diagonalr   s    r8   max_dimensionzBuilder.max_dimension   s(     59IItyy%%'00F3Fr>   c                    | j                   
t               S | j                  g n| j                  g}t        || j                  z   d| j                   iS )z(Edges that changed during last operationcombined)r   r%   rx   r*   ry   )rz   before_lists     r8   r*   zBuilder.new_edges   sJ     99; OO3b$//9J;8NDIINNr>   c                &   t         j                         }t        j                         }|r|r|j                  |j
                  k(  nd}|r|| _        nd| _        | j                  j                  |       | _	        t        j                  dt        |       j                  | j                  |rdnd       | j                  r't!        | j                   j#                         | _        | S t!        t&        j(                        j#                         | _        | S )zBUpon entering record the parent and a token to restore contextvarsFNz7Entering %s with mode=%s which is in %s scope as parentsame	different)ra   _get_contextro   rp   rr   rq   rt   re   rC   rn   loggerinfotype__name__rh   rm   rj   	__enter__rv   r   rl   )rz   builder_contextr|   
same_scopes       r8   r   zBuilder.__enter__  s     +2*>*>*@,,. = ))]-A-AA 	 "1D"&D--++D1EJII Fk		
 ??&3T__&E&O&O&QD#  '4EHH&=&G&G&ID#r>   c                     y)z!Any builder specific exit actionsN r   s    r8   _exit_extraszBuilder._exit_extras)  s    r>   c                   | j                   j                  | j                         | j                          | j                  | j
                  t        j                  k7  rt        j                  dt        | j                        j                         | j                  Ht        j                         d   s1t        j                   | j"                   d| j$                   dd       | j                  j'                  | j                  | j
                         t(        j+                         j,                  | _        | j,                  r| j0                  j3                  ddd       t        j5                  d	t        |       j                         y)
z6Upon exiting restore context and send object to parentNzTransferring object(s) to %sr-   z is None - z didn't create anything   )
stacklevelrg   z
Exiting %s)re   resetrn   r   rt   rh   r   PRIVATEr   debugr   r   r   sysexc_infowarningswarn	_obj_name_tag_add_to_contextrj   r   rm   rw   rv   __exit__r   rz   exception_typeexception_value	tracebacks       r8   r   zBuilder.__exit__,  s   DOO,*tyyDLL/HLL.T5H5H0I0R0R yy ):~~&k$))<ST  //				/J,99;FF ??##,,T4>L$t*"5"56r>   N)
face_planec                   t         S )z<Integrate a sequence of objects into existing builder objectr   )rz   r   objectss      r8   _add_to_pendingzBuilder._add_to_pendingF  s
     #"r>   Tc                T   | j                   j                  d      }|dnt        |      j                  }|rct	        |t
        t        t        t        f      r|j                  j                  }nt	        |t              r|}nd}t        j                  d||       t        t        |      S )z*Return the instance of the current builderNrf   z%s context requested by %s)re   getr   r   r3   r#   r&   r   r)   	__class__strr   r   r   r`   )clscallerlogresultcontext_namecaller_names         r8   r   zBuilder._get_contextK  s     !!$'!'vT&\5J5J&4"=>$..77FC($$KK4lKPAvr>   )faces_to_pendingcleanrh   c          	     V   | j                   | _        t        |      | _        |t        j
                  k7  r)t        |      dkD  rt        t        t        t        t        fD ci c]  }|g  c}}t        t        t        t        t        fD ]"  }|D cg c]  }t        ||      s| c}||<   $ t        d |j                         D              }t        |      |k7  rjt        j                          d   sSt#        |      |j                         D 	
ch c]  }	|	D ]  }
|
  c}
}	z
  }|dhk7  rt%        | j&                   d|       |t           D ]@  }t        t        t        t        fD ]%  }||   j)                  |j+                  |             ' B | j&                  dk(  rg }|t           D ]  }|j-                  t.        j0                        sd	 t/        dd|j3                         	      }|j9                  |      }|j;                  t=        dd|j?                         j@                   f             |j3                         j@                  dkD  r|jC                  |       |jC                  |         ||t        <   |t           D ](  }|t           j)                  |jE                                * |s(|t           j)                  |t                  g |t        <   i }tF        t        t        t        fD ]5  }| j                   
t#               nt#        | jI                  |            ||<   7 || jJ                     rltL        jO                  dt        || jJ                           |       |}|t        jP                  k(  r| j                   jt        || jJ                           dk(  r|| jJ                     d   }nO || jJ                     jS                         jT                  || jJ                      }d}n | j                   jT                  || jJ                      }d}n|t        jV                  k(  r@| j                   tY        d       | j                   jZ                  || jJ                      }d}n|t        j\                  k(  rK| j                   tY        d      | j                   j_                  t        || jJ                                 }d}n:|t        j`                  k(  r'| jc                  t        || jJ                                 }| jc                         | _         n.t        |t              r| jc                  |      | _         n|| _         | j                   !|r| j                   je                         | _         tL        jg                  dt        || jJ                           |       tF        t        t        t        fD ]m  }| j                   
t#               nt#        | jI                  |            }| jJ                  |k(  rti        ||         nti        |||   z
        | jj                  |<   o | j                   |t        | j                   t              r+| jc                  | j                   jl                        | _         n7| jc                  t        | jI                               jl                        | _         | j&                  dk(  rq | jn                  |t             tp        js                         jt                  D ]9  }|t           D cg c]  }|jw                  |       }} | jn                  |d|i ; y| j&                  dk(  r | jn                  |t             yyyyc c}w c c}w c c}
}	w # t4        t$        t6        f$ r t/        d|j3                         
      }Y w xY wc c}w )a  Add objects to Builder instance

        Core method to interface with Builder instance. Input sequence of objects is
        parsed into lists of edges, faces, and solids. Edges and faces are added to pending
        lists. Solids are combined with current part.

        Each operation generates a list of vertices, edges, faces, and solids that have
        changed during this operation. These lists are only guaranteed to be valid up until
        the next operation as subsequent operations can eliminate these objects.

        Args:
            objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
            faces_to_pending (bool, optional): add faces to pending_faces. Default to True.
            clean (bool, optional): Remove extraneous internal structure. Defaults to True.
            mode (Mode, optional): combination mode. Defaults to Mode.ADD.

        Raises:
            ValueError: Invalid input
            ValueError: Nothing to intersect with
            ValueError: Nothing to intersect with
        r   c              3  2   K   | ]  }t        |        y wr2   )len)r6   ts     r8   r9   z*Builder._add_to_context.<locals>.<genexpr>  s     <SV<s   r-   N doesn't accept rJ   )r   r   r   )r-   r   r   )originx_dirz_dir)r   r   z;Attempting to integrate %d object(s) into part with Mode=%sFzNothing to subtract fromzNothing to intersect withz9Completed integrating %d object(s) into part with Mode=%srI   r   )<r   rx   rA   ry   r   r   r   r    r)   r!   r'   r   r3   sumvaluesr   r   rC   
ValueErrorr   rD   get_typeis_coplanarr   rl   	normal_at	TypeErrorr   to_local_coordsmover   centerZrF   edgesr(   _shapes_shaper   r   ADDpopfuseSUBTRACTRuntimeErrorcut	INTERSECT	intersectREPLACE
_sub_classr   r   r%   ru   wrappedr   rj   r   rm   from_local_coords)rz   r   r   rh   r   r   typedr<   
num_storedlvunsupportedcompound	obj_typesalignednew_faceplanenew_wirepreneeds_cleanr   postfglobal_facess                           r8   r   zBuilder._add_to_context`  s   @ ))w-4<<CL1$4
 &*4uh$GHSbH  dD%: N-4Mc
38LcMc
N <U\\^<<J7|z)#,,.2C!'l-SAQR-SAa-Sa-SS4&($		{2B;-%PQQ "(O J"&dE!: JI)$++H,=,=i,HIJJ
 yyM) %d 2H#//9X$)'0&/&.&8&8&:%E $)#8#8#B h1x7H7J7J6J/K&LM))+--1x0y1#2$ &d "$K 5d""8>>#345 $e##E$K0 d CdE2 R$(II$5353t||C?P;QCR T[[!Qdkk*+ $488#yy(uT[[12a7',T[['9!'<H !>dkk 2 6 6 8 = =uT[[?Q R % +0K#1499>>53E#F&+T]]*yy(*+EFF,tyy}}eDKK.@AH"'KT^^+yy(*+FGG#yy228E$++<N3OPH"'KT\\)#tE$++4F/GHH# $ 1DId !% 9DI (DI 99([ $		 1DIOdkk*+ dE2  $		 1sus4<<;L7M {{c) eCj)"4#c(?3 

3 yy$dii2 $		0A0A BDI $0H0P0P QDI yyK'$$$eDk2*779DD JEHMd#T1E$;$;A$>#TL#T(D((,I5IJ m+$$$eDk2 ,g %5
 IM .T. !*:7QR X$)(BTBTBV$WEXZ $Us0   "
] ]%#]%]*]0^&0/^#"^#c                   g }|t         j                  k(  rO| j                  g n| j                  j                         }|D ]!  }|j	                  |j                                # na|t         j                  k(  r| j                  t           }n:|t         j                  k(  rt        d      t        dt         j                         t        t        |            S )a	  Return Vertices

        Return either all or the vertices created during the last operation.

        Args:
            select (Select, optional): Vertex selector. Defaults to Select.ALL.

        Returns:
            ShapeList[Vertex]: Vertices extracted
        Select.NEW only valid for edges%Invalid input, must be one of Select.)r   ALLr   r   rD   verticesLASTru   r(   NEWr   _member_names_r%   rC   )rz   selectvertex_list	obj_edgesobj_edges        r8   r   zBuilder.vertices  s     %'VZZ"ii/TYY__5FI% 8""8#4#4#678v{{"**V,Kvzz!>??78M8M7NO  [)**r>   c                j    | j                  |      }t        |      }|dk7  rt        d|       |d   S )zReturn Vertex

        Return a vertex.

        Args:
            select (Select, optional): Vertex selector. Defaults to Select.ALL.

        Returns:
            Vertex: Vertex extracted
        r-   z#Expected exactly one vertex, found r   )r   r   r   )rz   r   all_verticesvertex_counts       r8   vertexzBuilder.vertex4  sA     }}V,<(1B<.QRRAr>   c                   |t         j                  k(  r;| j                  
t               n| j                  j	                         }t        |      S |t         j
                  k(  r| j                  t           }t        |      S |t         j                  k(  r| j                  }t        |      S t        dt         j                         )zReturn Edges

        Return either all or the edges created during the last operation.

        Args:
            select (Select, optional): Edge selector. Defaults to Select.ALL.

        Returns:
            ShapeList[Edge]: Edges extracted
        r   )r   r   r   r%   r   r   ru   r    r   r*   r   r   )rz   r   	edge_lists      r8   r   zBuilder.edgesE  s     VZZ'+yy'8	diioo>OI ## v{{"

4(I ## vzz!I
 ## 78M8M7NO r>   c                j    | j                  |      }t        |      }|dk7  rt        d|       |d   S )zReturn Edge

        Return an edge.

        Args:
            select (Select, optional): Edge selector. Defaults to Select.ALL.

        Returns:
            Edge: Edge extracted
        r-   z!Expected exactly one edge, found r   )r   r   r   )rz   r   	all_edges
edge_counts       r8   edgezBuilder.edge\  ?     JJv&	^
?@MNN|r>   c                   |t         j                  k(  r;| j                  
t               n| j                  j	                         }t        |      S |t         j
                  k(  r1t        j                  | j                  t                 }t        |      S |t         j                  k(  rt        d      t        dt         j                         )zReturn Wires

        Return either all or the wires created during the last operation.

        Args:
            select (Select, optional): Wire selector. Defaults to Select.ALL.

        Returns:
            ShapeList[Wire]: Wires extracted
        r   r   )r   r   r   r%   wiresr   r)   combineru   r    r   r   r   )rz   r   	wire_lists      r8   r  zBuilder.wiresm  s     VZZ'+yy'8	diioo>OI ## v{{"TZZ%56I ## vzz!>??78M8M7NO r>   c                j    | j                  |      }t        |      }|dk7  rt        d|       |d   S )zReturn Wire

        Return a wire.

        Args:
            select (Select, optional): Wire selector. Defaults to Select.ALL.

        Returns:
            Wire: Wire extracted
        r-   z!Expected exactly one wire, found r   )r  r   r   )rz   r   	all_wires
wire_counts       r8   wirezBuilder.wire  r  r>   c                t   |t         j                  k(  r;| j                  
t               n| j                  j	                         }t        |      S |t         j
                  k(  r| j                  t           }t        |      S |t         j                  k(  rt        d      t        dt         j                         )zReturn Faces

        Return either all or the faces created during the last operation.

        Args:
            select (Select, optional): Face selector. Defaults to Select.ALL.

        Returns:
            ShapeList[Face]: Faces extracted
        r   r   )r   r   r   r%   facesr   ru   r!   r   r   r   )rz   r   	face_lists      r8   r  zBuilder.faces  s     VZZ'+yy'8	diioo>OI ## v{{"

4(I ## vzz!>??78M8M7NO r>   c                j    | j                  |      }t        |      }|dk7  rt        d|       |d   S )zReturn Face

        Return a face.

        Args:
            select (Select, optional): Face selector. Defaults to Select.ALL.

        Returns:
            Face: Face extracted
        r-   z!Expected exactly one face, found r   )r  r   r   )rz   r   	all_faces
face_counts       r8   facezBuilder.face  r  r>   c                t   |t         j                  k(  r;| j                  
t               n| j                  j	                         }t        |      S |t         j
                  k(  r| j                  t           }t        |      S |t         j                  k(  rt        d      t        dt         j                         )a  Return Solids

        Return either all or the solids created during the last operation.

        Args:
            select (Select, optional): Solid selector. Defaults to Select.ALL.

        Returns:
            ShapeList[Solid]: Solids extracted
        r   r   )r   r   r   r%   solidsr   ru   r'   r   r   r   )rz   r   
solid_lists      r8   r  zBuilder.solids  s     VZZ(,		(9tyy?O?O?QJ $$ v{{"E*J $$ vzz!>??78M8M7NO r>   c                j    | j                  |      }t        |      }|dk7  rt        d|       |d   S )zReturn Solid

        Return a solid.

        Args:
            select (Select, optional): Solid selector. Defaults to Select.ALL.

        Returns:
            Solid: Solid extracted
        r-   z"Expected exactly one solid, found r   )r  r   r   )rz   r   
all_solidssolid_counts       r8   solidzBuilder.solid  s@     [[(
*o!A+OPP!}r>   c                z   || j                   n|}| j                  
t               S |t        k(  r| j                  j	                         S |t
        k(  r| j                  j                         S |t        k(  r| j                  j                         S |t        k(  r| j                  j                         S t               S )zExtract Shapes)r   r   r%   r(   r   r    r   r!   r  r'   r  )rz   obj_types     r8   r   zBuilder._shapes  s    
 #+"24;;99;v99%%''t99??$$t99??$$u99##%%{r>   c           
        |sg }nt        |t              s|g}t        |t        t        t        t
        f      ru| j                  |j                  vr]t        | j                  j                   d|j                  j                   d|j                  j                   d|j                   d      t        |t              r8| j                  j                  t        |   vrt        d| dt        |    d      |D ]d  }t        |t              r|n|j                  j                  }|.t        |t              r?t        | dt        |      j                   d	| d
       y)z5Validate that objects/operations and parameters applyz doesn't have a z object or operation (z applies to )(z doesn't apply to Nr   z, did you intend <keyword>=?)r3   r   r#   r&   r   r)   r   _applies_tor   r   r   r   operations_apply_tor$   r   )rz   validating_classr   r<   	operations        r8   validate_inputszBuilder.validate_inputs  sx   
 GGX.iG '$t)DE		!1!=!==>>**++;#--667 8$..778EUEaEaDbbce  '-''/BCS/TT$%%78KL\8]7^^_`   	C .4 !%//88 
 {U+" k!1$s)2D2D1E F114Q8 	r>   c                `    t        | j                  j                   d| j                   d      )z5Raise an error for invalid boolean combine operationszc is a builder of Shapes and can't be combined. The object being constructed is accessible via the 'z' attribute.)r   r   r   r   r   s    r8   _invalid_combinezBuilder._invalid_combine!  s5    ~~&&' (|-
 	
r>   c                "    | j                         S )zInvalid addr'  rz   _others     r8   __add__zBuilder.__add__)      $$&&r>   c                "    | j                         S )zInvalid subr)  r*  s     r8   __sub__zBuilder.__sub__-  r-  r>   c                "    | j                         S )zInvalid andr)  r*  s     r8   __and__zBuilder.__and__1  r-  r>   c                    t        d| j                  j                   d| d| j                  j                   d| j                   d| d      )z;The user is likely trying to reference the builder's object'z' has no attribute 'z'. Did you intend '<z>..z'?)AttributeErrorr   r   r   )rz   names     r8   __getattr__zBuilder.__getattr__5  sX    ''((<TF C  $ 7 784>>:J!D6QSU
 	
r>   )rm   Face | Plane | Locationrh   r   )returnzShape | None)r   r#   r9  rf   )r9  r5   )r9  ShapeList[Edge])r9  r   )r   zEdge | Facer   zPlane | None)NT)r   zType[B]r   z$Builder | Shape | Joint | str | Noner   boolr9  zB | None)r   z%Edge | Wire | Face | Solid | Compoundr   r;  r   r;  rh   r   )r   r   r9  zShapeList[Vertex])r   r   r9  r(   )r   r   r9  r:  )r   r   r9  r    )r   r   r9  zShapeList[Wire])r   r   r9  r)   )r   r   r9  zShapeList[Face])r   r   r9  r!   )r   r   r9  zShapeList[Solid])r   r   r9  r'   r2   )r  z;Type[Vertex] | Type[Edge] | Type[Face] | Type[Solid] | Noner9  r%   )r   zShape | Iterable[Shape] | None)-r   
__module____qualname____doc__contextvars
ContextVarre   __annotations__r   r   r   r   r}   propertyr   r   setterr   r*   r   r   r   r   classmethodr   r   r   r   r   r   r   r  r  r  r  r  r  r  r   r%  r'  r,  r/  r1  r7  r   r>   r8   ra   ra      s:   $ 1G0F0F1H- 
 DI XX*,* ** "  " 
[["  " G G O O#J074 PT # #  8<4  
	 . "&XXv37v3 v3 	v3
 v3t )/

 +4 '-jj " &,ZZ $. %+JJ " &,ZZ $. %+JJ " &,ZZ $. %+JJ " '-jj %. &,ZZ & QUM 
( KO')G'R
'''
r>   c                .    | y| j                  ||       y)zDA function to wrap the method when used outside of a Builder contextN)r%  )contextr#  r   s      r8   r%  r%  =  s      0':r>   c                  |    e Zd ZU dZ ej
                  d      Zded<   edd       Z	ddZ
d Zd Zd	 Zed
        Zy)LocationLista`  Location Context

    A stateful context of active locations. At least one must be active
    at all time. Note that local locations are stored and global locations
    are returned as a property of the local locations and the currently
    active workplanes.

    Args:
        locations (list[Location]): list of locations to add to the context

    zContextList._currentz$contextvars.ContextVar[LocationList]re   c                    t         j                         }|r|j                  nt        j                  g}|D cg c]"  }| j
                  D ]  }|j                  |z   $ }}}|S c c}}w )z:Current local locations globalized with current workplanes)rj   r   rm   r   rl   local_locationslocation)rz   rF  rm   r   local_locationglobal_locationss         r8   	locationszLocationList.locationsY  sx      ,,.+2W''

 $
"&"6"6
  NN^+
+
 

  
s   'A%c                     d | _         || _        y r2   )rn   rJ  )rz   rN  s     r8   r}   zLocationList.__init__e  s    (r>   c                    | j                   j                  |       | _        t        j	                  dt        |       j                  t        | j                        | j                         | S )3Upon entering create a token to restore contextvarsz%s is pushing %d points: %s)	re   rC   rn   r   r   r   r   r   rJ  r   s    r8   r   zLocationList.__enter__i  sR    --++D1)J$$%  		
 r>   c                    | j                   j                  | j                         t        j	                  dt        |       j                  t        | j                               y)Upon exiting restore contextz%s is popping %d pointsN)	re   r   rn   r   r   r   r   r   rJ  r   s       r8   r   zLocationList.__exit__u  s@    DOO,%tDz':':C@T@T<U	
r>   c                ,    t        | j                        S r2   )iterrN  r   s    r8   __iter__zLocationList.__iter__|  s    DNN##r>   c                8    | j                   j                  d      S )z/Return the instance of the current LocationListNre   r   r   s    r8   r   zLocationList._get_context       ||%%r>   N)r9  list[Location])rN  r[  )r   r<  r=  r>  r?  r@  re   rA  rB  rN  r}   r   r   rV  rD  r   r   r>   r8   rH  rH  G  sc    
 6L[5K5K6H2  	  	 )

$ & &r>   rH  c                  h     e Zd ZdZdej
                  ej
                  ff	 	 	 	 	 	 	 	 	 d fdZ xZS )HexLocationsau  Location Context: Hex Array

    Creates a context of hexagon array of locations for Part or Sketch. When creating
    hex locations for an array of circles, set `radius` to the radius of the circle
    plus one half the spacing between the circles.

    Args:
        radius (float): distance from origin to vertices (major), or
            optionally from the origin to side (minor or apothem)
            with major_radius = False
        x_count (int): number of points ( > 0 )
        y_count (int): number of points ( > 0 )
        major_radius (bool): If True the radius is the major radius, else the
            radius is the minor radius (also known as inscribed radius).
            Defaults to False.
        align (Union[Align, tuple[Align, Align]], optional): align min, center, or max of object.
            Defaults to (Align.CENTER, Align.CENTER).

    Attributes:
        radius (float): distance from origin to vertices (major), or
            optionally from the origin to side (minor or apothem)
            with major_radius = False
        apothem (float): radius of the inscribed circle, also known as minor radius
        x_count (int): number of points ( > 0 )
        y_count (int): number of points ( > 0 )
        major_radius (bool): If True the radius is the major radius, else the
            radius is the minor radius (also known as inscribed radius).
        align (Union[Align, tuple[Align, Align]]): align min, center, or max of object.
        diagonal (float): major radius
        local_locations (list{Location}): locations relative to workplane

    Raises:
        ValueError: Spacing and count must be > 0
    Fc           
        |rd|z  }|t        t        dz        z  }nd|z  t        d      z  }|}d|z  dz  }|t        d      z  dz  }	|dk  s|	dk  s
|dk  s|dk  rt        d      || _        || _        || _        || _        || _        || _	        t        |d      | _        t        t                  }
t        d|d      D ]9  }t        |      D ])  }|
j                  t        ||z  |	|z  |	dz  z                + ; t        d|d      D ]6  }t        |      D ]&  }|
j                  t        ||z  |	|z  |	z                ( 8 |
j!                  t"        j$                        |
j!                  t"        j&                        g}|d   d   j$                  |d   d   j$                  z
  |d   d   j&                  |d   d   j&                  z
  g}t        |d   d   j$                  |d   d   j&                        }t)        d	||      }t        |
D cg c]  }|t        | z   |z
   c}      }
|
D cg c]  }t+        |       }}t,        j/                  |      | _        t2        | i  | j0                         y c c}w c c}w )
Nr            r   r-   zSpacing and count must be > 0 r   r   )r	   r
   r   r   radiusapothemr   x_county_countmajor_radiusr+   alignr%   r   rangerF   sort_byr   XYr   r   	Locations_move_to_existingrJ  superr}   )rz   rd  rf  rg  rh  ri  r   re  	x_spacing	y_spacingpointsx_valy_valsorted_pointssize
min_corneralign_offsetpointrJ  r   s                      r8   r}   zHexLocations.__init__  s    6zHs26{*G6zDG+HGL1$	tAw&*	>Y!^w{gk=>> (UA&
 6"$1gq) 	Ew 9u,i%.?)a-.OP	
 1gq) 	XEw XfY%6	E8II8UVWX	X
  /1GH !R ""]1%5a%8%:%::!R ""]1%5a%8%:%::
 M!,Q/11=3CA3F3H3HI
 'vtU; EKLEUV\**Z7L

 9??u8E???(:: 
 	--. M @s   I7/I<)
rd  r5   rf  r4   rg  r4   rh  r;  ri  Align | tuple[Align, Align]r   r<  r=  r>  r   CENTERr}   __classcell__r   s   @r8   r]  r]    s_    !P #.3llELL-IB/B/ B/ 	B/
 B/ +B/ B/r>   r]  c                  D     e Zd ZdZ	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 d fdZ xZS )PolarLocationsa  Location Context: Polar Array

    Creates a context of polar array of locations for Part or Sketch

    Args:
        radius (float): array radius
        count (int): Number of points to push
        start_angle (float, optional): angle to first point from +ve X axis. Defaults to 0.0.
        angular_range (float, optional): magnitude of array from start angle. Defaults to 360.0.
        rotate (bool, optional): Align locations with arc tangents. Defaults to True.
        endpoint (bool, optional): If True, `start_angle` + `angular_range` is the last sample.
            Otherwise, it is not included. Defaults to False.

    Attributes:
        local_locations (list{Location}): locations relative to workplane

    Raises:
        ValueError: Count must be greater than or equal to 1
    c                   |dk  rt        d|       |dk(  rd}n||t        |      z
  z  }g }t        |      D ]`  }	|j                  t	        t        |d      j                  t        j                  |||	z  z         t        ddd      |||	z  |z   z               b t        j                  |      | _        t        
| 5  | j                         y )Nr-   (At least 1 elements required, requested r   r   )r   r4   rj  rF   r   r   rotater   r   rn  ro  rJ  rp  r}   )rz   rd  countstart_angleangular_ranger  endpoint
angle_steprJ  ir   s             r8   r}   zPolarLocations.__init__  s     19GwOPPA:J&%#h-*?@J u 	A""61%,,TVV[:PQ>5QR1aOj1n{:;	  ):: 
 	--.r>   )r   g     v@TF)rd  r5   r  r4   r  r5   r  r5   r  r;  r  r;  )r   r<  r=  r>  r}   r~  r  s   @r8   r  r    sZ    0 !$// / 	/
 / / / /r>   r  c                  :     e Zd ZdZ	 	 d fdZedd       Z xZS )rn  aA  Location Context: Push Points

    Creates a context of locations for Part or Sketch

    Args:
        pts (Union[VectorLike, Vertex, Location, Face, Plane, Axis] or iterable of same):
            sequence of points to push

    Attributes:
        local_locations (list{Location}): locations relative to workplane

    c                <   g }t        | D ]Z  }t        |t              r|j                  |       &t        |t              r|j                  t        |             Qt        |t
              r$|j                  t        t	        |                   t        |t              r$|j                  t        t	        |                   t        |t              r|j                  t        |             t        |t              r|j                  |j                         t        |t              r%|j                  t        t        |                   Ft        dt        |              t        j                  |      | _        t         | E  | j                         y )NzLocations doesn't accept type )rE   r3   r   rF   r   r(   r:   r   r   rK  r!   r   r   rn  ro  rJ  rp  r}   )rz   ptsrJ  rz  r   s       r8   r}   zLocations.__init__3  s3    %s+ 	QE%*&&u-E6*&&x7E6*&&xu'>?E5)&&xu'>?E5)&&x7E4(&&u~~6E4(&&xe'=> #A$u+!OPP!	Q$  ):: 
 	--.r>   c                    g }t         j                         Gt         j                         j                  D ]$  }|j                  | D cg c]  }||z  	 c}       & |S | }|S c c}w )a  _move_to_existing

        Move as a group the local locations to any existing locations  Note that existing
        polar locations may be rotated so this rotates the group not the individuals.

        Args:
            local_locations (list[Location]): location group to move to existing locations

        Returns:
            list[Location]: group of locations moved to existing locations as a group
        )rH  r   rJ  rD   )rJ  location_groupgroup_centerr   s       r8   ro  zLocations._move_to_existingW  sq     $$&2 , 9 9 ; K K S%%&QA|a'7&QRS  -N 'Rs   A"
)r  zuVectorLike | Vertex | Location | Face | Plane | Axis | Iterable[VectorLike | Vertex | Location | Face | Plane | Axis])rJ  r[  r9  r[  )r   r<  r=  r>  r}   staticmethodro  r~  r  s   @r8   rn  rn  %  s-    "/M"/H  r>   rn  c                  f     e Zd ZdZej
                  ej
                  ff	 	 	 	 	 	 	 	 	 d fdZ xZS )GridLocationsa  Location Context: Rectangular Array

    Creates a context of rectangular array of locations for Part or Sketch

    Args:
        x_spacing (float): horizontal spacing
        y_spacing (float): vertical spacing
        x_count (int): number of horizontal points
        y_count (int): number of vertical points
        align (Union[Align, tuple[Align, Align]], optional): align min, center, or max of object.
            Defaults to (Align.CENTER, Align.CENTER).


    Attributes:
        x_spacing (float): horizontal spacing
        y_spacing (float): vertical spacing
        x_count (int): number of horizontal points
        y_count (int): number of vertical points
        align (Union[Align, tuple[Align, Align]]): align min, center, or max of object.
        local_locations (list{Location}): locations relative to workplane

    Raises:
        ValueError: Either x or y count must be greater than or equal to one.
    c                L   |dk  s|dk  rt        d| d|       || _        || _        || _        || _        t        |d      | _        ||dz
  z  ||dz
  z  g}t        | | _        t        d||      }|| _
        | j                  | j                  z   | _        t        t        |      t        |            D 	cg c]#  \  }}	t        |t        ||z  |	|z        z         % }
}}	t        j!                  |
      | _        g | _        t&        | Q  | j"                         y c c}	}w )Nr-   r  z, r   rc  )r   rq  rr  rf  rg  r+   ri  r   rw  r   minmaxr   rj  r   rn  ro  rJ  r{   rp  r}   )rz   rq  rr  rf  rg  ri  rw  ry  r  jrJ  r   s              r8   r}   zGridLocations.__init__  s;    Q;'A+:7)2gYO  #"UA&
Wq[)9!+DEDM	&vtU;88dii'  gg?	
 1 	M	M	
 	
  ):: 
 $&--.	
s   :(D )
rq  r5   rr  r5   rf  r4   rg  r4   ri  r{  r|  r  s   @r8   r  r  m  sU    B /4llELL-I*/*/ */ 	*/
 */ +*/ */r>   r  c                      e Zd ZU dZ ej
                  d      Zded<   ddZe	dd       Z
d Zd Zd	 Zed
        Zeedd              Zeedd              Zedd       Zy)rj   a  Workplane Context

    A stateful context of active workplanes. At least one must be active
    at all time.

    Args:
        workplanes (sequence of Union[Face, Plane, Location]): objects to become planes

    Attributes:
        workplanes (list[Plane]): list of workplanes

    zWorkplaneList._currentz%contextvars.ContextVar[WorkplaneList]re   c                T    d | _         t        j                  |      | _        d | _        y r2   )rn   rj   rk   rm   locations_context)rz   rm   s     r8   r}   zWorkplaneList.__init__  s#    ':::F!%r>   c                    t        |  } g }| D ]k  }t        |t              r|j                  |       %t        |t        t
        f      r|j                  t        |             Vt        dt        |              |S )zTranslate objects to planeszWorkplaneList does not accept )rE   r3   r   rF   r   r!   r   r   )objsr{   r<   s      r8   rk   z WorkplaneList._convert_to_planes  sw      & 	OC#u%c"C(D!12eCj) #A$s)!MNN	O r>   c                6   | j                   j                  |       | _        t        j	                  dt        |       j                  t        | j                        | j                         t        t        t                     g      j                         | _        | S )rQ  z%s is pushing %d workplanes: %s)re   rC   rn   r   r   r   r   r   rm   rH  r   r   r   r  r   s    r8   r   zWorkplaneList.__enter__  sn    --++D1-J OO		
 ".x/A.B!C!M!M!Or>   c                   | j                   j                  | j                         | j                  j	                  ddd       t
        j                  dt        |       j                  t        | j                               y)rS  Nz%s is popping %d workplanes)re   r   rn   r  r   r   r   r   r   r   rm   r   s       r8   r   zWorkplaneList.__exit__  sV    DOO,''dD9)4:+>+>DOO@T	
r>   c                ,    t        | j                        S r2   )rU  rm   r   s    r8   rV  zWorkplaneList.__iter__  s    DOO$$r>   c                8    | j                   j                  d      S )z.Return the instance of the current ContextListNrX  rY  s    r8   r   zWorkplaneList._get_context  rZ  r>   c                     y r2   r   r   rs  s     r8   localizezWorkplaneList.localize  s    58r>   c                     y r2   r   r  s     r8   r  zWorkplaneList.localize  s    <?r>   c                   t         j                         |D cg c]  }t        |       }}ng }t         j                         j                  d   }|D cg c]E  }t	        |t
              r(t        t        |j                  t        |                  n
t        |      G }}t        |      dk(  r|j                  |d          n|j                  |       t        |      dk(  r|d   S |S c c}w c c}w )zLocalize a sequence of points to the active workplane
        (only used by BuildLine where there is only one active workplane)

        The return value is conditional:
        - 1 point -> Vector
        - >1 points -> list[Vector]
        r   r-   )rj   r   r   rm   r3   r:   r   r   r   rF   rD   )r   rs  ppoints_per_workplane	workplaneptlocalized_ptss          r8   r  zWorkplaneList.localize   s     %%'/7=#>!F1I#> #>#% %224??BI !  ""e, !<!<VBZ!HI$M  =!Q&$++M!,<=$++M:#$)'**##' $?s   C*A
C/N)rm   r8  )r  z!Iterable[Face | Plane | Location]r9  zlist[Plane])rs  r   r9  r   )rs  r   r9  zlist[Vector])rs  r   )r   r<  r=  r>  r?  r@  re   rA  r}   r  rk   r   r   rV  rD  r   r   r  r   r>   r8   rj   rj     s     7Mk6L6L 7H3 &
  

% & & 8  8?  ?$ $r>   rj   T2c                d     t        j                         t        j                  fd fd       }|S )ao  
    Wraps a Builder method to automatically provide the Builder context.

    This function creates a wrapper around the provided Builder method (`func`) that
    automatically retrieves the current Builder context and passes it as the first
    argument to the method. This allows the method to be called without explicitly
    providing the Builder context.

    Args:
        func (Callable[[Builder, Select], T2]): The Builder method to be wrapped.
            - The method must take a `Builder` instance as its first argument and
              a `Select` instance as its second argument.

    Returns:
        Callable[T2]: A callable that takes only a `Select` argument and
        internally retrieves the Builder context to call the original method.

    Raises:
        RuntimeError: If no Builder context is available when the returned function
        is called.
    c                    t         j                  j                        }|t        j                   d       ||       S )Nz,() requires a Builder context to be in scope)ra   r   r   r   )r   rF  funcs     r8   getterz.__gen_context_component_getter.<locals>.getter=  sI     #*"6"6t}}"E?==/!MN  GV$$r>   )r   r   r9  r  )	functoolswrapsr   r   )r  r  s   ` r8   __gen_context_component_getterr  $  s.    2 __T &

 % % Mr>   c                     d fd}|S )Nc                    t        |t              rD	 t        j                         j                  d   j
                  }t        j                  |      |z
  } | |      S # t        $ r Y w xY w)Nr   )r3   r:   rj   r   rm   r   r  r5  )rz   vecr   original_ops      r8   wrapperz(_vector_add_sub_wrapper.<locals>.wrapper^  si    c5!&335@@CJJ#,,S1F: 4%% " s   AA 	A+*A+)rz   r   r  r   r   )r  r  s   ` r8   _vector_add_sub_wrapperr  ]  s    	& Nr>   z-monkey-patching `Vector.add` and `Vector.sub`)r<   r?   r9  zShapeList[Any]r2   )rF  zBuilder | Noner   zIterable[Shape] | None)r  zCallable[[Builder, Select], T2]r9  zCallable[[Select], T2])r  z&Callable[[Vector, VectorLike], Vector])ir>  
__future__r   r?  r  ro   loggingr   r   abcr   r   collections.abcr   r   	itertoolsr   mathr	   r
   r   typingr   r   r   r   r   r   OCP.Standardr   typing_extensionsr   build123d.build_enumsr   r   r   r   build123d.geometryr   r   r   r   r   r   build123d.topologyr   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   	getLogger
addHandlerNullHandlerr   MCMMCMMINFTTHOUUNITS_PER_METERGKGLBr=   rA   r?   rE   r"  r`   rc   ra   r%  rH  r]  r  rn  r  rj   r  r  r   r   r  r  r  r   r  r  r  r  r  r   rH   subr   r>   r8   <module>r     s  'R #     
  # .    > > 3 " ; ;    *   +  ) )*='*=*=*? @			;	'  "W2I	BY"W	Dy 	GGQVGGQVGGQVGGQVGGQVFFA 	AX] Cd3i 	4= 8 k]	
 } 7 =/ [M + - - 7 7 8 +  }!" 6#$ }6=)}+ 0 Cy! 		' *@

c76? @

H RV;;8N;;& ;&|f/< f/R4/\ 4/nE EPF/L F/Rg$ g$V T]$
)$$P *'*:*:;&w}}5&w}}5&w}}5	'	7	'	7%gll3%gll3%gll3&w}}5 < =$VZZ0
$VZZ0
r>   