
    ^j                   v   d Z ddlm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
 ddl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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(m)Z) ddl*m+Z+m,Z, ddl-m.Z.m/Z/ ddl0m1Z1 ddl2m3Z3m4Z4 ddl5m6Z6m7Z7 ddl8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z> ddl?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZH ddlImJZJ ddlKmLZL ddlMmNZN ddlOmPZPmQZQ ddlRmSZS ddlTmUZU ddlVmWZW ddlXmYZY ddlZm[Z[ ddl\m]Z] ddl^m_Z_ ddl`maZambZbmcZcmdZdmeZemfZfmgZgmhZh dd limjZj dd!lkmlZl dd"lmmnZnmoZo dd#lpmqZq dd$lrmsZs dd%l$mtZtmuZu dd&lvmwZwmxZx dd'lymzZz dd(l{m|Z|m}Z}m~Z~mZmZmZmZmZmZmZmZ dd)lmZmZmZmZ dd*lmZmZ dd+lmZmZmZmZmZ dd,lmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ er(dd-lmZ d.d/lmZ d.d0lmZmZ d.d1lmZ d.d2lmZmZ d.d3lmZ ed4   Zeed5d6f   Z ed7e8      Zeeejgdf   Zeed9   gd9f   Z G d: d9e(ee         Z G d; d<e      Z G d= d>e      Z ed?eeef   8      Z ed@e8      Z G dA dBeeef         Z	 	 	 	 dUdCZ G dD dEee         Z G dF dGe      Z G dH dI      ZdVdJZ	 	 	 	 	 	 	 	 dWdKZdXdLZdYdMZdZdNZdZdOZ	 	 	 	 d[dPZd\dQZd]dRZ	 d^	 	 	 	 	 d_dSZ	 	 	 	 d`dTZy)aa  
build123d topology

name: shape_core.py
by:   Gumyr
date: January 07, 2025

desc:

This module defines the foundational classes and methods for the build123d CAD library, enabling
detailed geometric operations and 3D modeling capabilities. It provides a hierarchy of classes
representing various geometric entities like vertices, edges, wires, faces, shells, solids, and
compounds. These classes are designed to work seamlessly with the OpenCascade Python bindings,
leveraging its robust CAD kernel.

Key Features:
- **Shape Base Class:** Implements core functionalities such as transformations (rotation,
  translation, scaling), geometric queries, and boolean operations (cut, fuse, intersect).
- **Custom Utilities:** Includes helper classes like `ShapeList` for advanced filtering, sorting,
  and grouping of shapes, and `GroupBy` for organizing shapes by specific criteria.
- **Type Safety:** Extensive use of Python typing features ensures clarity and correctness in type
  handling.
- **Advanced Geometry:** Supports operations like finding intersections, computing bounding boxes,
  projecting faces, and generating triangulated meshes.

The module is designed for extensibility, enabling developers to build complex 3D assemblies and
perform detailed CAD operations programmatically while maintaining a clean and structured API.

license:

    Copyright 2025 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)deque)CallableIterableIterator)reduce)inf)
TYPE_CHECKINGAnyClassVarGenericLiteralOptionalProtocolSupportsIndexTypeVarUnioncast)overload)	NodeMixin
RenderTree)RepresentationPrinterpretty)Bnd_BoxBnd_OBB)BOPAlgo_GlueEnum)
BRep_TEdge	BRep_Tool)BRepAdaptor_CurveBRepAdaptor_Surface)BRepAlgoAPI_BooleanOperationBRepAlgoAPI_CommonBRepAlgoAPI_CutBRepAlgoAPI_FuseBRepAlgoAPI_SectionBRepAlgoAPI_Splitter)	BRepBuilderAPI_CopyBRepBuilderAPI_GTransformBRepBuilderAPI_MakeFaceBRepBuilderAPI_MakeVertexBRepBuilderAPI_RightCornerBRepBuilderAPI_RoundCornerBRepBuilderAPI_SewingBRepBuilderAPI_TransformBRepBuilderAPI_Transformed)BRepCheck_Analyzer)BRepExtrema_DistShapeShape)BRepFeat_SplitShape)	BRepGPropBRepGProp_Face)BRepIntCurveSurface_Inter)BRepMesh_IncrementalMesh)BRepPrimAPI_MakeHalfSpace)	BRepTools)gce_MakeLin)GeomAPI_ProjectPointOnSurf)GeomLib_IsPlanarSurface)gp_Ax1gp_Ax2gp_Ax3gp_Dirgp_Pntgp_Trsfgp_Vecgp_XYZ)GProp_GProps)ShapeAnalysis_Curve)ShapeCustom!ShapeCustom_RestrictionParameters)ShapeFix_Shape)ShapeUpgrade_UnifySameDomain)TopAbs_OrientationTopAbs_ShapeEnum)TopExpTopExp_Explorer)TopLoc_Location)TopoDSTopoDS_BuilderTopoDS_CompoundTopoDS_EdgeTopoDS_FaceTopoDS_IteratorTopoDS_ShapeTopoDS_ShellTopoDS_SolidTopoDS_VertexTopoDS_Wire))TopTools_IndexedDataMapOfShapeListOfShapeTopTools_ListOfShapeTopTools_SequenceOfShapeTopTools_ShapeMapHasher)Self
deprecated)CenterOfGeomTypeKeepSortBy
Transition)DEG2RAD	TOLERANCEAxisBoundBoxColor	ColorLikeLocationMatrixNotAllLocationLikeErrorOrientedBoundBoxPlaneVector
VectorLikeall_location_likelogger)	BuildPart   )Compound)EdgeWire)Solid)FaceShell)Vertex)r   rz   r{   r}   r~   r|   ry   r~   r}   TOPODS)boundShapec                     e Zd ZU dZi Zded<   ej                  dej                  dej                  dej                  dej                  dej                  d	ej                  d
ej                  diZej                  dej                  ej"                  ej                  ej"                  ej                  ej$                  ej                  ej$                  ej                  ej&                  ej                  ej&                  ej                  ej&                  iZded<   ej+                         D  ci c]  \  }}||
 c}}} Zej                  ej0                  ej                  ej2                  ej                  ej4                  ej                  ej6                  ej                  ej8                  ej                  ej:                  ej                  ej<                  ej                  ej>                  iZ e!jD                  e#jH                  e!jJ                  e#jL                  e!jN                  e#jP                  e!jR                  e#jT                  e!jV                  e#jX                  e!jZ                  e#j\                  e!j^                  e#j`                  e!jb                  e#jd                  e!jf                  e#jh                  i	Z5ded<   e!jl                  e#jn                  e!jp                  e#jr                  e!jt                  e#jv                  e!jx                  e#jz                  e!j|                  e#j~                  e!j                  e#j\                  e!j                  e#j`                  e!j                  e#j                  e!j                  e#j                  e!j                  e#jd                  e!j                  e#jh                  iZHded<   eIj                  eKeIj                  eMeIj                  eOiZPded<    G d deQ      ZReSj                  eSj                  eSj                  eSj                  eSj                  eSj                  eSj                  eSj                  gZT	 	 	 	 d	 	 	 	 	 	 	 ddZUeVd        ZWeWj                  dd       ZWd ZYeVeZdd              Z[eVdd       Z\eVdd       Z]e]j                  dd       Z]eVdd       Z^eVdd        Z_eVdd!       Z`eV ead"      dd#              ZbeVdd$       ZceVdd%       ZdeVdd&       Zeeej                  dd'       ZeeVdd(       ZfeVdd)       Zgegj                  dd*       ZgeVdd+       Zhehj                  dd,       ZheVdd-       ZieVdd.       ZjeVdd/       ZkeleZdd0              ZmeleZ	 	 	 	 	 	 dd1              ZneodeSj                  d2f	 	 	 	 	 	 	 	 	 	 	 dd3       Zpeodd4       Zqeoerj                  f	 	 	 	 	 dd5       Zteodd6       Zueveo	 	 	 	 	 	 dd7              Zweveo	 	 	 	 	 	 dd8              Zweveo	 	 	 	 	 	 dd9              Zweveo	 	 	 	 	 	 dd:              Zweveo	 	 	 	 	 	 dd;              Zweveo	 	 	 	 	 	 dd<              Zweveo	 	 	 	 	 	 dd=              Zweo	 	 	 	 	 	 dd>       Zweveodd?              Zxeveodd@              ZxeveoddA              ZxeveoddB              ZxeveoddC              ZxeveoddD              Zxeveo	 	 	 	 	 	 ddE              Zxeo	 	 	 	 	 	 ddF       Zxel	 	 	 	 	 	 ddG       Zyel	 d	 	 	 	 	 ddH       ZzevddI       Z{evddJ       Z{dK Z{ddLZ|ddMZ}ddNZ~ddOZddPZevddQ       ZevddR       ZddSZevddT       ZevddU       ZdV Z	 d	 	 	 	 	 ddWZddXZddYZddZZdd[Z	 d	 	 	 dd\Zdd]Zdd^Zdd_Z	 	 	 	 dd`ZddaZddbZddcZdddZddeZddfZ	 d	 	 	 	 	 ddgZddhZdiddj	 	 	 	 	 	 	 ddkZddlZdmdidn	 	 	 	 	 	 	 ddoZ	 	 d	 	 	 	 	 	 	 ddpZdddqZddrZddsZddtZdduZdddvZdddwZddxZddyZddzZ	 d	 	 	 	 	 	 	 dd{Zdd|Zdd}Zddd~Z	 d	 	 	 	 	 ddZddZddZ	 	 d	 	 	 	 	 ddZddZddZev	 	 	 	 	 	 dd       Zevd d       Zevdd       Zev	 	 	 	 	 	 dd       Zevdd       Zej^                  fddZev	 	 	 	 	 	 dd       Zev	 	 	 	 	 	 dd       Zevejb                  f	 	 	 	 	 dd       Z ead      ejb                  fdd       Z	 d	 	 	 	 	 d	dZ	 d
	 	 	 	 	 	 	 ddZddZddZ	 d	 	 	 	 	 ddZdddZddZddZddZ	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 ddZd ZddZddZyc c}}} w (  r   a  Shape

    Base class for all CAD objects such as Edge, Face, Solid, etc.

    Args:
        obj (TopoDS_Shape, optional): OCCT object. Defaults to None.
        label (str, optional): Defaults to ''.
        color (ColorLike, optional): Defaults to None.
        parent (Compound, optional): assembly parent. Defaults to None.

    Attributes:
        wrapped (TopoDS_Shape): the OCP object
        label (str): user assigned label
        color (Color): object color
        joints (dict[str:Joint]): dictionary of joints bound to this object (Solid only)
        children (Shape): list of assembly children of this object (Compound only)
        topo_parent (Shape): assembly parent of this object

    z,ClassVar[dict[int | None, CompositeFactory]]composite_factoriesr   rz   r{   r}   r~   r|   ry   	CompSolidNz%dict[TopAbs_ShapeEnum, CalcFn | None]shape_properties_LUTz$dict[ga.GeomAbs_CurveType, GeomType]geom_LUT_EDGEz&dict[ga.GeomAbs_SurfaceType, GeomType]geom_LUT_FACEzColor | None_colorc                  0    e Zd ZdZ	 	 	 	 d	 	 	 	 	 	 	 ddZy)Shape._DisplayNodez4Used to create anytree structures from TopoDS_ShapesNc                J    || _         || _        || _        || _        g | _        y N)labeladdresspositionparentchildren)selfr   r   r   r   s        V/opt/ringagent/.cad-venv/lib/python3.12/site-packages/build123d/topology/shape_core.py__init__zShape._DisplayNode.__init__  s'     DJ"DL$DM DK)+DM    ) NNN)r   strr   
int | Noner   zVector | Location | Noner   zShape._DisplayNode | None)__name__
__module____qualname____doc__r    r   r   _DisplayNoder   	  s>    B "&1504	,	,  	, /		,
 .	,r   r   c                    | t        t        t           t        |            nd | _        d| _        || _        || _        || _        d | _	        y NF)
tcastr   r   downcast_wrappedfor_constructionr   colorr   topo_parent)r   objr   r   r   s        r   r   zShape.__init__%  sO     7:oE(6"HSM24 	 !&

  *.r   c                6    | j                   sJ | j                   S )zOCP TopoDS objectr   r   s    r   wrappedzShape.wrapped=  s     }}}}}r   c                    || _         y r   r   r   shapes     r   r   zShape.wrappedC  s	    r   c                    | j                   d uS r   r   r   s    r   __bool__zShape.__bool__G  s    }}D((r   c                     y)zDimension of the objectNr   r   s    r   _dimz
Shape._dimJ      r   c                    | j                   yt               }t        j                  | j                  |       |j                         S )z1area -the surface area of all faces in this Shape        )r   rG   r6   SurfaceProperties_sr   Massr   
propertiess     r   areaz
Shape.areaO  s9     == !^
%%dllJ?  r   c                    | j                   %| }||j                   }|n|j                  }|}n| j                   }|| _         |S )zGet the shape's color.  If it's None, get the color of the nearest
        ancestor, assign it to this Shape and return this value.)r   r   )r   current_nodeparent_color
node_colors       r   r   zShape.colorY  s]    
 ;;48L*+22++22	 *
 &JJ r   c                8    |t        |      | _        yd| _        y)zSet the shape's colorN)rl   r   r   values     r   r   zShape.colorl  s     ',&7eElTr   c                   | j                   t        d      t        | j                        }|t        j
                  k(  rDt        j                  t        t        t        | j                              j                            }|S |t        j                  k(  rDt        j                  t        t        t        | j                              j                            }|S t         j"                  }|S )zsGets the underlying geometry type.

        Returns:
            GeomType: The geometry type of the shape

        z0Cannot determine geometry type of an empty shape)r   
ValueError	shapetyper   taTopAbs_EDGEr   r   r"   r   rU   GetTypeTopAbs_FACEr   r#   rV   rd   OTHER)r   r   geoms      r   	geom_typezShape.geom_typeq  s     == OPP"+DLL"9BNN"&&!%T\\"BCKKMD  bnn$&&#E+t||$DEMMOD  >>Dr   c                   | j                   yt        | j                        }|r|j                  d      }t	               }t        j                  |t        j                  t        j                  |       t        |j                               D ]  }t        j                  |j                  |dz               }t               }t               }t        j                   |||       |j#                         r"|j#                         r|j%                  |      r|j'                  |dz         j                         dk7  s y |ry)zis_manifold

        Check if each edge in the given Shape has exactly two faces associated with it
        (skipping degenerate edges). If so, the shape is manifold.

        Returns:
            bool: is the shape manifold or water tight
        Fr   rx      T)r   get_top_level_topods_shapesr   popr]   rO   MapShapesAndAncestors_sr   r   r   rangeExtentrR   rz   FindKeyr[   
Vertices_sIsNullIsSameFindFromIndex)r   shape_stackr   	shape_mapiedgevertex0vertex1s           r   is_manifoldzShape.is_manifold  s    == 1$,,?OOA&E BCI ** 9++-. !{{9#4#4QU#;<'/'/ !!$9 >>#(8W^^G=T
 **1q5188:a? '!% N r   c                V    | j                   du xs | j                  j                         S )zReturns true if this shape is null. In other words, it references no
        underlying shape with the potential to be given a location and an
        orientation.
        N)r   r   r   r   s    r   is_nullzShape.is_null  s%     }}$=(;(;(==r   zqThe 'is_planar_face' property is deprecated and will be removed in a future version. Use 'Face.is_planar' insteadc                    | j                   t        | j                  t              syt	        j
                  | j                        }t        |t              }|j                         S )zEIs the shape a planar face even though its geom_type may not be PLANEF)	r   
isinstancer   rV   r!   	Surface_sr>   ri   IsPlanar)r   surfaceis_face_planars      r   is_planar_facezShape.is_planar_face  sM     == 
4<<(M%%dll30)D&&((r   c                    | j                   yt        | j                        }|j                  d       |j	                         S )zReturns True if no defect is detected on the shape S or any of its
        subshapes. See the OCCT docs on BRepCheck_Analyzer::IsValid for a full
        description of what is checked.
        T)r   r3   r   SetParallelIsValid)r   chks     r   is_validzShape.is_valid  s7     ==  .{{}r   c                B    t        d | j                  t                     S )aS  
        The location of this Shape relative to the global coordinate system.

        This property computes the composite transformation by traversing the
        hierarchy from the root of the assembly to this node, combining the
        location of each ancestor. It reflects the absolute position and
        orientation of the shape in world space, even when the shape is deeply
        nested within an assembly.

        Note:
            This is only meaningful when the Shape is part of an assembly tree
            where parent-child relationships define relative placements.
        c                     | |j                   z  S r   )location)locns     r   <lambda>z'Shape.global_location.<locals>.<lambda>  s    S1::%5 r   )r
   pathrn   r   s    r   global_locationzShape.global_location  s     5tyy(*MMr   c                v    | j                   t        d      t        | j                  j                               S )zGet this Shape's Locationz)Can't find the location of an empty shape)r   r   rn   r   r   s    r   r   zShape.location  s2     == HII--/00r   c                h    | j                   &| j                   j                  |j                          yy)zSet Shape's Location to valueN)r   rn   r   s     r   r   zShape.location  s)     <<#LL!!%--0 $r   c                R   | j                   t        d      t               }t        j                  | j
                  |       |j                         }g }t        d      D ]@  }|j                  t        d      D cg c]  }|j                  |dz   |dz          c}       B |S c c}w )u  
        Compute the inertia matrix (moment of inertia tensor) of the shape.

        The inertia matrix represents how the mass of the shape is distributed
        with respect to its reference frame. It is a 3×3 symmetric tensor that
        describes the resistance of the shape to rotational motion around
        different axes.

        Returns:
            list[list[float]]: A 3×3 nested list representing the inertia matrix.
            The elements of the matrix are given as:

            | Ixx  Ixy  Ixz |
            | Ixy  Iyy  Iyz |
            | Ixz  Iyz  Izz |

            where:
            - Ixx, Iyy, Izz are the moments of inertia about the X, Y, and Z axes.
            - Ixy, Ixz, Iyz are the products of inertia.

        Example:
            >>> obj = MyShape()
            >>> obj.matrix_of_inertia
            [[1000.0, 50.0, 0.0],
            [50.0, 1200.0, 0.0],
            [0.0, 0.0, 300.0]]

        Notes:
            - The inertia matrix is computed relative to the shape's center of mass.
            - It is commonly used in structural analysis, mechanical simulations,
              and physics-based motion calculations.
        z&Can't calculate matrix for empty shape   rx   )
r   r   rG   r6   VolumeProperties_sr   MatrixOfInertiar   appendValue)r   r   inertia_matrixmatrixr   js         r   matrix_of_inertiazShape.matrix_of_inertia  s    D == EFF!^
$$T\\:>#335q 	RAMMuQxP!>//Aq1u=PQ	R Qs   :B$
c                \    | j                   t        d      | j                   j                  S )z6Get the orientation component of this Shape's Locationz,Can't find the orientation of an empty shape)r   r   orientationr   s    r   r  zShape.orientation.  s*     == KLL}}(((r   c                P    | j                   }|t        |      |_        || _         yy)zCSet the orientation component of this Shape's Location to rotationsN)r   rs   r  )r   	rotationsr   s      r   r  zShape.orientation5  s*     mm?$Y/CODM r   c                t    | j                   | j                  t        d      | j                  j                  S )z3Get the position component of this Shape's Locationz)Can't find the position of an empty shape)r   r   r   r   r   s    r   r   zShape.position=  s3     == DMM$9HII}}%%%r   c                P    | j                   }|t        |      |_        || _         yy)z<Set the position component of this Shape's Location to valueN)r   rs   r   )r   r   r   s      r   r   zShape.positionD  s)     mm?!%=CLDM r   c                v   | j                   t        d      t               }t        j                  | j
                  |       |j                         }|j                         }t        |j                               |d   ft        |j                               |d   ft        |j                               |d   fgS )a  
        Compute the principal moments of inertia and their corresponding axes.

        Returns:
            list[tuple[Vector, float]]: A list of tuples, where each tuple contains:
            - A `Vector` representing the axis of inertia.
            - A `float` representing the moment of inertia for that axis.

        Example:
            >>> obj = MyShape()
            >>> obj.principal_properties
            [(Vector(1, 0, 0), 1200.0),
            (Vector(0, 1, 0), 1000.0),
            (Vector(0, 0, 1), 300.0)]
        z*Can't calculate properties for empty shaper   rx   r   )r   r   rG   r6   r   r   PrincipalPropertiesMomentsrs   FirstAxisOfInertiaSecondAxisOfInertiaThirdAxisOfInertia)r   r   principal_propsprincipal_momentss       r   principal_propertieszShape.principal_propertiesL  s    " == IJJ!^
$$T\\:>$88:+335O6689;LQ;OPO779:<Ma<PQO6689;LQ;OP
 	
r   c                j    t        t        t        j                  t	        | j
                                 S )z+Return the shape type string for this class)r   Shapesr   	shape_LUTr   r   r   s    r   
shape_typezShape.shape_typej  s#     VU__Yt||-DEFFr   c                    | j                   t        d      t               }t        j                  | j
                  |       |j                         S )a  
        Compute the static moments (first moments of mass) of the shape.

        The static moments represent the weighted sum of the coordinates
        with respect to the mass distribution, providing insight into the
        center of mass and mass distribution of the shape.

        Returns:
            tuple[float, float, float]: The static moments (Mx, My, Mz),
            where:
            - Mx is the first moment of mass about the YZ plane.
            - My is the first moment of mass about the XZ plane.
            - Mz is the first moment of mass about the XY plane.

        Example:
            >>> obj = MyShape()
            >>> obj.static_moments
            (150.0, 200.0, 50.0)

        z'Can't calculate moments for empty shape)r   r   rG   r6   r   r   StaticMomentsr   s     r   static_momentszShape.static_momentso  sD    , == FGG!^
$$T\\:>''))r   c                     y)z6Returns the right type of wrapper, given a OCCT objectNr   )clsr   s     r   r   z
Shape.cast  r   r   c                     y)a  extrude

        Extrude a Shape in the provided direction.
        * Vertices generate Edges
        * Edges generate Faces
        * Wires generate Shells
        * Faces generate Solids
        * Shells generate Compounds

        Args:
            direction (VectorLike): direction and magnitude of extrusion

        Raises:
            ValueError: Unsupported class
            RuntimeError: Generated invalid result

        Returns:
            Edge | Face | Shell | Solid | Compound: extruded shape
        Nr   )r  r   	directions      r   extrudezShape.extrude  r   r   Tc                   t         j                  | j                            }|r(t        |       j                         j	                         }nt        | j                               }|j                  t         j                  |t        |       ||             t               }|j                  |        |d   }|j                         r|j                         }	t         j                  j                  |	j                               t         j                  j                  |      k  rt         j                  |	|||       |j!                          |j                         r|S )z4Create an anytree copy of the TopoDS_Shape structure)r   r  	ShapeTypebounding_boxcenterrn   r   r   idrW   
InitializeMorer   _ordered_shapesindex_build_treeNext)
r   treer   limitshow_centerobj_typer   iteratorparent_nodechilds
             r   r'  zShape._build_tree  s    ??5??#45,++-446C5>>+,CE&&xECHI"$E"2hmmoNN$E$$**!&&,,U34 !!%{EBMMO mmo r   c           
        | j                   D cg c]#  }|j                  t        |j                        f% }}|j	                  | j                  t        | j                        f       t        | j                  dz         D cg c]  t        t        fd|             }}|D cg c]  }t        dt        d |D                      }}t        t        |            D cg c]  \  }}||dz  z    }	}}t        |	      dz   }
d}t        |       D ]  \  }}}| |j                   j                  |
      }t        | d      r1|j                  }d}|rd|j                  dnd	|j                  d}n[t!        |      }|j"                  j$                  j                  d
      }|rd|j'                         dnt)        |j*                        }|| | d|dd| dz  } |S c c}w c c}w c c}w c c}}w )z5Display an assembly or TopoDS_Shape anytree structurerx   c                    | d   k(  S Nr   r   )llls    r   r   z"Shape._show_tree.<locals>.<lambda>  s    2a5A: r      c              3  &   K   | ]	  }|d      yw)rx   Nr   ).0r4  s     r   	<genexpr>z#Shape._show_tree.<locals>.<genexpr>  s     +qt+s   r   r   Centerz.6gPosition	   zat z#xz, 
)descendantsheightlenr   r   r   listfiltermax	enumeratereversedr   ljusthasattrr   r   r"  	__class__r   r!  reprr   )	root_noder+  nodesize_tuplesr4  size_tuples_per_levellevelmax_sizes_per_levelr   level_sizes_per_leveltree_label_widthresultpre_filltreestrr   namer   s       `             r   
_show_treezShape._show_tree  s   
 CLBWBWX$S_5XXI,,c)//.BCD 9++a/0!
 -{;<!
 !

 ;P
16C3+U++,
 
 #,H5H,I"J!
!QAAI!
 !
 459  *9 5 	ACdjj\*001ABGy),,, # T]]3/0#DMM##67  T(~~..44Q74?fT[[]3/0T$--EX  	$s72,bR@@F!	A" E Y!

!
s   (G)G.*#G3&G8c                   t        |       } |t        j                  k(  rt        d | D              }| D cg c]C  }|j	                  t        j                        j                  t        j                  |            E }}|d   }|dd D ]  }|j                  |      } t        |j                  d|z              }|S |t        j                  k(  rt        t        |             }g }| D ]/  }|j                  |j                         j	                                1 |d   }|dd D ]  }|j                  |      } t        |j                  d|z              }|S t        d      c c}w )ay  combined center

        Calculates the center of a multiple objects.

        Args:
            objects (Iterable[Shape]): list of objects
            center_of (CenterOf, optional): centering option. Defaults to CenterOf.MASS.

        Raises:
            ValueError: CenterOf.GEOMETRY not implemented

        Returns:
            Vector: center of multiple objects
        c              3  F   K   | ]  }t         j                  |        y wr   )r   compute_massr7  os     r   r8  z(Shape.combined_center.<locals>.<genexpr>  s     DqU//2Ds   !r   rx   N      ?z!CenterOf.GEOMETRY not implemented)r@  rc   MASSsumr!  multiplyr   rY  addrs   BOUNDING_BOXr?  r   r   r   )	objects	center_of
total_massr[  weighted_centerssum_wcweighted_centermiddler   s	            r   combined_centerzShape.combined_center  so   $ w-%DGDDJQX LM'001C1CA1FG    &a(F#3AB#7 5O45FOOC*,<=>F   (///T']+J! E ''(8(8(:(A(A(CDE &a(F#3AB#7 5O45 FOOC*,<=>F  @AA+ s   AE%c                    | syt               }t        j                  t        | j                           }|t
         || j                  |       |j                         S )zCalculates the 'mass' of an object.

        Args:
          obj: Compute the mass of this object
          obj: Shape:

        Returns:

        r   )rG   r   r   r   r   NotImplementedErrorr   )r   r   calc_functions      r   rY  zShape.compute_mass"  sQ     !^
229S[[3IJ %%ckk:.  r   c                     y r   r   r   entity_types     r   get_shape_listzShape.get_shape_list9  s      r   c                     y r   r   rn  s     r   rp  zShape.get_shape_list?       r   c                     y r   r   rn  s     r   rp  zShape.get_shape_listE  rr  r   c                     y r   r   rn  s     r   rp  zShape.get_shape_listK  rr  r   c                     y r   r   rn  s     r   rp  zShape.get_shape_listQ       r   c                     y r   r   rn  s     r   rp  zShape.get_shape_listW  rv  r   c                     y r   r   rn  s     r   rp  zShape.get_shape_list]  s     "r   c                    | s
t               S t        | j                  |      D cg c]  }| j                  j                  |       c}      }|D ]!  }| j                  | n| j                  |_        # |S c c}w )z;Helper to extract entities of a specific type from a shape.)	ShapeListentitiesrG  r   r   )r   ro  r   
shape_listitems        r   rp  zShape.get_shape_listc  sy     ;.3nn[.IJU__!!!$J

  	YD(-(9(9(AuuGXGXD	Y	 Ks   "A6c                     y r   r   rn  s     r   get_single_shapezShape.get_single_shapet  s    RUr   c                     y r   r   rn  s     r   r  zShape.get_single_shapex      NQr   c                     y r   r   rn  s     r   r  zShape.get_single_shape|  r  r   c                     y r   r   rn  s     r   r  zShape.get_single_shape  r  r   c                     y r   r   rn  s     r   r  zShape.get_single_shape      PSr   c                     y r   r   rn  s     r   r  zShape.get_single_shape  r  r   c                     y r   r   rn  s     r   r  zShape.get_single_shape  s     r   c                    t         j                  | |      }t        |      }|dk7  rt        d|j	                          d|       |d   S )zReturn the single entity of the requested type.

        Raises:
            ValueError: if the number of matching entities is not exactly one.
        rx   zExpected exactly one z, found r   )r   rp  r?  r   lower)r   ro  r|  entity_counts       r   r  zShape.get_single_shape  sZ     ))%=
:1'(9(9(;'<H\NS  !}r   c                "    || j                   |<   y)z;Register a composite constructor without importing it here.N)r   )r  	dimensionfactorys      r   register_composite_factoryz Shape.register_composite_factory  s     .5	*r   c                6   t        |      }|;|r9|D ch c]  }|j                   }}t        |      dk(  r|j                         nd}| j                  j                  |      xs | j                  j                  d      }|t        d       ||      S c c}w )z/Build the registered composite for a dimension.Nrx   z#Composite factory is not registered)rz  r   r?  r   r   getRuntimeError)r  shapesr  r|  r   
dimensionsr  s          r   make_compositezShape.make_composite  s     v&
2<=%**=J=,/
Oq,@
(dI))--i8 
C<S<S<W<W=
 ?DEEz"" >s   Bc                     y r   r   r   others     r   __add__zShape.__add__      ,/r   c                     y r   r   r  s     r   r  zShape.__add__      JMr   c                   |g }n;t        |t              r|gn|D cg c]  }||j                         D ]  }|  }}}|s| S | j                  t	        d      t        fd|D              st	        d      | j                  ,t        |      dk(  r|d   }|S  |d   j                  |dd  }|S  | j                  | }|S c c}}w )zfuse shape to self operator +Nz0Dimensions of objects to add to are inconsistentc              3  <   K   | ]  }|j                   k(    y wr   r   )r7  summand
addend_dims     r   r8  z Shape.__add__.<locals>.<genexpr>  s     F'7<<:-F   z0Only shapes with the same dimension can be addedrx   r   )	r   r   get_top_level_shapesr   r   allr   r?  fuse)r   r  summandsr[  r   	sum_shaper  s         @r   r  zShape.__add__  s    =H
 &0u%=5'5 =335
 	 H  K YY
OPPFXFFOPP== 8}!$QK	 	 -HQK,,hqrl;	  "		8,I7s    Cc                f   t        |t        t        f      r|n|g}| rt        |t              r|st	        d       | j
                  | }t        |t              r)t        |      dk(  r|d   }nt        j                  |      }|,|j                   t        j                  r|j                         }|S )z$intersect shape with self operator &z*Cannot intersect shape with empty compoundrx   r   )r   r@  tupler   r   	intersectr?  r  r   	SkipCleanclean)r   r  others	new_shapes       r   __and__zShape.__and__  s    $UT5M:
5%0IJJ"DNNF+	i&9~"%aL	!00;	 Y%6%6%By!)Ir   c                    t        j                  |       }| j                  A|j                  J |j                  j                  | j                  j                                |S )a  Return shallow copy or reference of self

        Create an copy of this Shape that shares the underlying TopoDS_TShape.

        Used when there is a need for many objects with the same CAD structure but at
        different Locations, etc. - for examples fasteners in a larger assembly. By
        sharing the TopoDS_TShape, the memory size of such assemblies can be greatly reduced.

        Changes to the CAD structure of the base object will be reflected in all instances.
        )copydeepcopyr   TShape)r   	references     r   __copy__zShape.__copy__  sW     MM$'	<<#!!--$$T\\%8%8%:;r   c           	        | j                   }|j                  |      }||t        |       <   | j                  Bt	        t        | j                        j                               |t        | j                        <   | j                  j                         D ]_  \  }}|dk(  r||_	        n!t        ||t        j                  ||             |dk(  s:|j                  j                         D ]	  }||_         a |S )zReturn deepcopy of selfr   joints)rG  __new__r"  r   r   r*   r   __dict__itemsr   setattrr  r  r  valuesr   )r   memor  rQ  keyr   joints          r   __deepcopy__zShape.__deepcopy__  s    
 nnS!RX<<#%-.A$,,.O.U.U.W%XDDLL!"----/ 	*JCm#%*"T]]5$%?@h#]]113 *E#)EL*	* r   c                P    t        |t              r| j                  |      S t        S )a  Check if two shapes are the same.

        This method checks if the current shape is the same as the other shape.
        Two shapes are considered the same if they share the same TShape with
        the same Locations. Orientations may differ.

        Args:
            other (Shape): The shape to compare with.

        Returns:
            bool: True if the shapes are the same, False otherwise.
        )r   r   is_sameNotImplementedr  s     r   __eq__zShape.__eq__!  s#     eU#<<&&r   c                F    | j                   yt        | j                        S )zReturn hash coder   )r   hashr   r   s    r   __hash__zShape.__hash__2  s    == DLL!!r   c                     y r   r   r  s     r   __rmul__zShape.__rmul__8  s    9<r   c                     y r   r   r  s     r   r  zShape.__rmul__:  s    ILr   c                   t        |t        t        z        r| j                  |      S 	 t	        |      D cg c]  }| j                  |       c}S c c}w # t
        $ r)}t        t        |       j                   d|       |d}~wt        $ r Y nw xY wt        t        |       j                   dt        |      j                         )z)right multiply for positioning operator *z cannot be multiplied by N)	r   rn   rr   movedru   rp   	TypeErrortyper   )r   r  r   es       r   r  zShape.__rmul__<  s    eX-.::e$$	/@/GHDJJsOHHH& 	YtDz2233LQCPQWXX 		Dz""##<T%[=Q=Q<RS
 	
s.   A AA A 	B $BBBc                     y r   r   r  s     r   __sub__zShape.__sub__J  r  r   c                     y r   r   r  s     r   r  zShape.__sub__L  r  r   c                J   | j                   t        d      |g }n;t        |t              r|gn|D cg c]  }||j	                         D ]  }|  }}}|s| S | j
                  t        d |D              rt        d      |D cg c]  }|j
                  |j
                   }}t        fd|D              rGt        dt        |       j                   d dt        |      j                   dt        |       d	       | j                  | }|S c c}}w c c}w )	zcut shape from self operator -z)Cannot subtract shape from empty compoundc              3  8   K   | ]  }|j                   d u   y wr   r  )r7  ss     r   r8  z Shape.__sub__.<locals>.<genexpr>e  s     %Jaffn%Js   z7Dimensions of objects to subtract from are inconsistentc              3  (   K   | ]	  }|k    y wr   r   )r7  dminuend_dims     r   r8  z Shape.__sub__.<locals>.<genexpr>j  s     81q;8s   zCOnly shapes with equal or greater dimension can be subtracted: not z (zD) and zD))r   r   r   r   r  r   anyr  r   mincut)	r   r  subtrahendsr[  r   r  subtrahend_dims
differencer  s	           @r   r  zShape.__sub__N  sM    == HII =K
 &0u%=5'5 =335
 	 K  K ii#%Jk%J"JVWW ,7Ma!&&:L166MM888Dz**+2k]';''(3+?*@D  TXX{+
9" Ns    DD D c                    | j                   t        t                     S |t        n|}t        j                  | j
                  ||      S )zCreate a bounding box for this Shape.

        Args:
            tolerance (float, optional): Defaults to None.

        Returns:
            BoundBox: A box sized to contain this Shape
        )	toleranceoptimal)r   rk   r   ri   from_topo_dsr   )r   r  r  s      r   r   zShape.bounding_boxv  sA     == GI&&!*!2I		$$T\\YPWXXr   c                B   | j                   | S t        | j                  ddd      }|j                  d       	 |j	                          t        t        t        |j                                     | _        | S # t        $ r t        j                  d|  d       Y | S w xY w)zclean

        Remove internal edges

        Returns:
            Shape: Original object with extraneous internal edges removed
        TFzUnable to clean r   
stacklevel)r   rL   r   AllowInternalEdgesBuildr   r   r   r   	Exceptionwarningswarn)r   upgraders     r   r  zShape.clean  s     == K/dD$O##E*	CNN (..2B)CDDL   	CMM,TF3B	Cs   <A7 7#BBc                *    | j                  |      dd S )z?Points on two shapes where the distance between them is minimalrx   r   distance_to_with_closest_pointsr  s     r   closest_pointszShape.closest_points  s    33E:1Q??r   c                .    t         j                  | d      S )Return the Compoundry   r   r  r   s    r   compoundzShape.compound  s    %%dJ77r   c                    t               S )z+compounds - all the compounds in this Shaperz  r   s    r   	compoundszShape.compounds  s
    {r   c           	        t        | j                  j                               }t        |j                  j                               }||z  }||t        |      z  }|D ]  }|dk(  rWt        ||      s$t	        j
                  | j                        |_        |j                  j                         D ]	  }||_         _t        ||      rlt        ||t        | |              y)a@  Copy common object attributes to target

        Note that preset attributes of target will not be overridden.

        Args:
            target (Shape): object to gain attributes
            exceptions (Iterable[str], optional): attributes not to copy

        Raises:
            ValueError: invalid attribute
        Nr  )
setr  keysgetattrr  r  r  r  r   r  )r   target
exceptionsattrs1attrs2common_attrsattrr  s           r   copy_attributes_tozShape.copy_attributes_to  s     T]]'')*V__))+,!C
O+L  	;Dxvt,$(MM$++$>FM#]]113 *E#)EL*VT*gdD&9:	;r   c                >    t               }| j                  | f||      S )zRemove the positional arguments from this Shape.

        Args:
          *to_cut: Shape:

        Returns:
            Self | Compound: Resulting object may be of a different class than self
        )r&   _bool_op)r   to_cutcut_ops      r   r  z	Shape.cut  s!     !"}}dWff55r   c                    | j                   |st        d      t        | j                  |j                        j	                         S )zfMinimal distance between two shapes

        Args:
          other: Shape:

        Returns:

        3Cannot calculate distance to or from an empty shape)r   r   r4   r   r   r  s     r   distancezShape.distance  s:     == RSS)$,,FLLNNr   c                *    | j                  |      d   S )z#Minimal distance between two shapesr   r  r  s     r   distance_tozShape.distance_to  s    33E:1==r   c                V   | j                   t        |t              r|st        d      t        |t              rt	        t
        |j                        }nMt        |      }t        t        |j                  |j                  |j                              j                         }t               }|j                  | j                         |j!                  |       |j#                          |j%                         t        |j'                  d            t        |j)                  d            fS )z@Minimal distance between two shapes and the points on each shaper  rx   )r   r   r   r   r   rX   r   rs   r-   rC   XYZr   r4   LoadS1LoadS2Performr   PointOnShape1PointOnShape2)r   r  topods_shapevec	dist_calcs        r   r  z%Shape.distance_to_with_closest_points  s     == Zu%=eRSSeU# u}}=L-C4suuceeSUU+fh  /0	&&OO9**1-.9**1-.
 	
r   c              '  &  K   | j                   t        d      t               }|j                  | j                         |D ]L  }|st        d      |j                  |j                         |j                          |j                          N yw)zwMinimal distances to between self and other shapes

        Args:
          *others: Shape:

        Returns:

        Nr  )r   r   r4   r  r   r  r  r   )r   r  r  other_shapes       r   	distanceszShape.distances  s      == RSS.0	&! 	$K !VWW[001//##	$s   BBc                .    t         j                  | d      S )Return the Edgerz   r  r   s    r   r   z
Shape.edge      %%dF33r   c                V    t         j                  | d      }|j                  d d      S )z=edges - all the edges in this Shape - subclasses may overriderz   c                @    t        j                  | j                        S r   )r!   Degenerated_sr   )r  s    r   r   zShape.edges.<locals>.<lambda>#  s    i--aii8 r   Treverse)r   rp  	filter_by)r   	edge_lists     r   edgeszShape.edges  s1    ((v6	""8$ # 
 	
r   c                J    | j                   g S t        | j                  |      S )z7Return all of the TopoDS sub entities of the given type)r   _topods_entitiesr   )r   	topo_types     r   r{  zShape.entities&  s"    == Ii88r   c                .    t         j                  | d      S )Return the Facer}   r  r   s    r   facez
Shape.face,  r  r   c                .    t         j                  | d      S )z#faces - all the faces in this Shaper}   r   rp  r   s    r   faceszShape.faces0      ##D&11r   c                   | j                   
t               S t        |j                        j	                         }t               }|j                  | j                  ||       g }|j                         r|j                         }|j                  j                         j                  |      }|j                  |j                         t        |      f       |j                          |j                         r|j!                  d        |D cg c]  }|d   	 }	}t        |	D cg c]  }| j"                  j%                  |       c}      S c c}w c c}w )a  Line Intersection

        Computes the intersections between the provided axis and the faces of this Shape

        Args:
            axis (Axis): Axis on which the intersection line rests
            tol (float, optional): Intersection tolerance. Defaults to 1e-4.

        Returns:
            list[Face]: A list of intersected faces sorted by distance from axis.position
        c                    | d   S Nrx   r   )xs    r   r   z1Shape.faces_intersected_by_axis.<locals>.<lambda>[  s
    ad r   r  r   )r   rz  r<   r   r   r8   Initr$  Pntr   to_pntSquareDistancer   r}   absr(  sortrG  r   )
r   axistollineintersect_maker
faces_distinter_ptr  r)  r,  s
             r   faces_intersected_by_axiszShape.faces_intersected_by_axis4  s     == ;4<<(..035T\\45
""$&**,H}}++-<<XFH#((*M   " ""$ 	N+%/0Ta00F$..--d3FGG 1Fs   E%"Ec                    | j                   | S | j                  s@t        j                  | d      }t	        t
        t        | j                              |_        |S | S )z#fix - try to fix shape if not validN)r   r   r  r  r   r   fixr   )r   
shape_copys     r   rA  z	Shape.fix`  sK    == K}} $dD 9J!&vs4<</@!AJr   F)gluer:  c                   t               }|r|j                  t        j                         |r|j	                  |       | j                  | f||      }|S )a  fuse

        Fuse a sequence of shapes into a single shape.

        Args:
            to_fuse (sequence Shape): shapes to fuse
            glue (bool, optional): performance improvement for some shapes. Defaults to False.
            tol (float, optional): tolerance. Defaults to None.

        Returns:
            Self | Compound: Resulting object may be of a different class than self

        )r'   SetGluer   BOPAlgo_GlueShiftSetFuzzyValuer  )r   rC  r:  to_fusefuse_opreturn_values         r   r  z
Shape.fusel  sM    " #$OO,>>?!!#&}}dWgw?r   c                ~      j                   
t               S t         fdt         j                        D              S )a2  
        Retrieve the first level of child shapes from the shape.

        This method collects all the non-compound shapes directly contained in the
        current shape. If the wrapped shape is a `TopoDS_Compound`, it traverses
        its immediate children and collects all shapes that are not further nested
        compounds. Nested compounds are traversed to gather their non-compound elements
        without returning the nested compound itself.

        Returns:
            ShapeList[Shape]: A list of all first-level non-compound child shapes.

        Example:
            If the current shape is a compound containing both simple shapes
            (e.g., edges, vertices) and other compounds, the method returns a list
            of only the simple shapes directly contained at the top level.
        c              3  T   K   | ]  }j                   j                  |       ! y wr   rG  r   )r7  r  r   s     r   r8  z-Shape.get_top_level_shapes.<locals>.<genexpr>  s%      
'(DNN"
   %()r   rz  r   r   r   s   `r   r  zShape.get_top_level_shapes  s:    $ == ; 
,G,U
 
 	
r   ư>)r  include_touchedc          	     |   |sy|D ]>  }t        |t        t        t        t        t
        f      r)t        dt        |              t        | g      }|D ]`  }t               }|D ]7  }|j                  |||      }|s|j                  |j                                9 |s yt        t        |            }b |r|S dS )u[  Find where bodies/interiors meet (overlap or crossing geometry).

        This is the main entry point for intersection operations. Handles
        geometry conversion and delegates to subclass _intersect() implementations.

        Semantics:
            - Multiple arguments use AND (chaining): c.intersect(s1, s2) = c ∩ s1 ∩ s2
            - Compound arguments use OR (distribution): c.intersect(Compound([s1, s2]))
              = (c ∩ s1) ∪ (c ∩ s2)

        Args:
            to_intersect: Shape(s) or geometry objects to intersect with
            tolerance: tolerance for intersection detection
            include_touched: if True, include boundary contacts without interior
                overlap (only relevant when Solids are involved)

        Returns:
            ShapeList of intersection results, or None if no intersection
        Nz Unsupported type for intersect: )r   r   rs   rn   rj   rr   r   r  rz  
_intersectextendexpandr  )	r   r  rP  to_intersectr   
common_setr  next_setrQ  s	            r   r  zShape.intersect  s    4    	QCcE68T5#IJ #CDI;!OPP	Q v&
! 	2E"++H! 5y/JOOFMMO45 "3x=1J	2 (z1T1r   c                     y)a  Single-object intersection implementation.

        Base implementation returns None. Subclasses (Vertex, Mixin1D, Mixin2D,
        Mixin3D, Compound) override this to provide actual intersection logic.

        Args:
            other: Shape or geometry object to intersect with
            tolerance: tolerance for intersection detection
            include_touched: if True, include boundary contacts

        Returns:
            ShapeList of intersection shapes, or None if no intersection
        Nr   )r   r  r  rP  s       r   rR  zShape._intersect  s    & r   c                    t               S )a  Find boundary contacts between this shape and another.

        Base implementation returns empty ShapeList. Subclasses (Mixin2D, Mixin3D,
        Compound) override this to provide actual touch detection.

        Args:
            other: Shape to find contacts with
            tolerance: tolerance for contact detection

        Returns:
            ShapeList of contact shapes (empty for base implementation)
        r  )r   r  r  s      r   touchzShape.touch  s     {r   c                j    | j                   |sy| j                  j                  |j                        S )zReturns True if two shapes are equal, i.e. if they share the same
        TShape with the same Locations and Orientations. Also see
        :py:meth:`is_same`.

        Args:
          other: Shape:

        Returns:

        F)r   r   IsEqualr  s     r   is_equalzShape.is_equal  s,     == ||##EMM22r   c                j    | j                   |sy| j                  j                  |j                        S )zReturns True if other and this shape are same, i.e. if they share the
        same TShape with the same Locations. Orientations may differ. Also see
        :py:meth:`is_equal`

        Args:
          other: Shape:

        Returns:

        F)r   r   r   r  s     r   r  zShape.is_same  s,     == ||""5==11r   c                ~    | j                   t        d      | j                  j                  |j                         | S )znApply a location in absolute sense to self

        Args:
          loc: Location:

        Returns:

        Cannot locate an empty shape)r   r   r   rn   r   r   s     r   locatezShape.locate,  s5     == ;<<ckk*r   c                    | j                   t        d      t        j                  | d      }|j                  j                  |j                         |S )zlocated

        Apply a location in absolute sense to a copy of self

        Args:
            loc (Location): new absolute location

        Returns:
            Shape: copy of Shape at location
        Nr`  )r   r   r  r  r   rn   r   r   rB  s      r   locatedzShape.located;  sH     == ;<<]]4.
##CKK0r   c                    | j                   t        d      t        j                  | j                  |      st        | j                  |d|d       yy)zGenerate triangulation if none exists.

        Args:
          tolerance: float:
          angular_tolerance: float:  (Default value = 0.1)

        Returns:

        NzCannot mesh an empty shapeT)r   r   r;   Triangulation_sr   r9   )r   r  angular_tolerances      r   meshz
Shape.meshL  sL     == 9::((yA$i/@$ Br   c                   |st         j                  }| j                  | S t               }|j	                  t        |j                  j                         |j                  j                                      | j                  |      S )z
        Applies a mirror transform to this Shape. Does not duplicate objects
        about the plane.

        Args:
          mirror_plane (Plane): The plane to mirror about. Defaults to Plane.XY
        Returns:
          The mirrored shape
        )rr   XYr   rD   	SetMirrorr@   originr5  z_dirto_dir_apply_transform)r   mirror_planetransformations      r   mirrorzShape.mirror^  so      88L== K   <&&--/1C1C1J1J1LM	
 $$^44r   c                ~    | j                   t        d      | j                  j                  |j                         | S )zApply a location in relative sense (i.e. update current location) to self

        Args:
          loc: Location:

        Returns:

        Cannot move an empty shape)r   r   r   Movera  s     r   movez
Shape.movet  s5     == 9::#++&r   c                   t        |t              r|j                  }| j                  t	        d      t        j                  | d      }t        t        t        | j                  j                  |j                                    |_
        |S )a  moved

        Apply a location in relative sense (i.e. update current location) to a copy of self

        Args:
            loc (Location | Plane): new location relative to current location

        Returns:
            Shape: copy of Shape moved to relative location
        Nru  )r   rr   r   r   r   r  r  r   r   r   r   Movedrd  s      r   r  zShape.moved  sj     c5!,,C== 9:: MM$5
"68DLL4F4Fs{{4S+TU
r   c                V    | j                   t        t                     S t        |       S )zCreate an oriented bounding box for this Shape.

        Returns:
            OrientedBoundBox: A box oriented and sized to contain this Shape
        )r   rq   r   r   s    r   oriented_bounding_boxzShape.oriented_bounding_box  s&     == #GI..%%r   c           
        |j                   }| j                         }t        |t        t        f      s6|j
                  *t        |j
                  t              r|j                         }|d   j                         j                  j                  }t        j                  dt        |             g }|D ]  }|j                         }	|	j                  j                  |	j                  j                  z   dz  }
||
|z
  |z  z   }|j                  |      }|j!                  |      }t#        |||z
        }| j%                  |      d   \  }}t'        |||      }|j)                  |j+                  t-        |
 ddf                  }t        j                  d|       |j/                  |j1                  | |dz        d           t        j                  dt        |             t3        |      S )aF  Projected Faces following the given path on Shape

        Project by positioning each face of to the shape along the path and
        projecting onto the surface.

        Note that projection may result in distortion depending on
        the shape at a position along the path.

        .. image:: projectText.png

        Args:
            faces (Union[list[Face], Compound]): faces to project
            path: Path on the Shape to follow
            start: Relative location on path to start the faces. Defaults to 0.

        Returns:
            The projected faces

        r   zprojecting %d face(s)r   )rm  x_dirrn  zprojecting face at %0.2fr  zfinished projecting '%d' faces)lengthr!  r   r@  r  r   rT   r,  r   r  r  rv   debugr?  rB  position_at
tangent_atrj   find_intersection_pointsrr   from_local_coordsr  rn   r   project_to_shaperz  )r   r,  r   startpath_lengthshape_centerfirst_face_min_xprojected_facesr)  bboxface_center_xrelative_position_on_wirepath_positionpath_tangentprojection_axissurface_pointsurface_normalsurface_normal_planeprojection_faces                      r   project_faceszShape.project_faces  s   4 kk{{} 54-0)5==/:KKME 80026688,c%j9  	D$$&D!XXZZ$((**49M)99[HH & !,,-FGM??+DEL"=,2NOO,0,I,I--)M> $)$L$  %9$J$J

8m^Q$:;<%O LL35NO""00~7JKAN)	0 	5s5zB))r   c                    | j                   t        d      t               }t        j                  | j
                  |       |j                  |j
                        S )uT  
        Compute the radius of gyration of the shape about a given axis.

        The radius of gyration represents the distance from the axis at which the entire
        mass of the shape could be concentrated without changing its moment of inertia.
        It provides insight into how mass is distributed relative to the axis and is
        useful in structural analysis, rotational dynamics, and mechanical simulations.

        Args:
            axis (Axis): The axis about which the radius of gyration is computed.
                        The axis should be defined in the same coordinate system
                        as the shape.

        Returns:
            float: The radius of gyration in the same units as the shape's dimensions.

        Example:
            >>> obj = MyShape()
            >>> axis = Axis((0, 0, 0), (0, 0, 1))
            >>> obj.radius_of_gyration(axis)
            5.47

        Notes:
            - The radius of gyration is computed based on the shape’s mass properties.
            - It is useful for evaluating structural stability and rotational behavior.
        z2Can't calculate radius of gyration for empty shape)r   r   rG   r6   r   r   RadiusOfGyration)r   r9  r   s      r   radius_of_gyrationzShape.radius_of_gyration  sJ    6 == QRR!^
$$T\\:>**4<<88r   c                t   t        j                  dt        d       | j                  t	        d      | j
                  |k7  rt               }|j                  | j
                  j                  j                                t               }|j                  |j                  j                                t               }|j                  ||       t        | j                  |dd      }t        t        t        |j!                                     | _        | j                  j#                  |j                         yy)zChange the location of self while keeping it geometrically similar

        Args:
            loc (Location): new location to set for self
        zwThe 'relocate' method is deprecated and will be removed in a future version.Use move, moved, locate, or located insteadr   r  NzCannot relocate an empty shapeT)r  r  DeprecationWarningr   r   r   rA   	Transformr   TransformationrD   SetDisplacementr1   r   r   r   r   rn   )r   r   old_axnew_axtrsfbuilders         r   relocatezShape.relocate
  s     	:		
 == =>>==CXFT]]22AACDXFS[[779:9D  0.t||T4NG '--/)BCDLLL!!#++.  r   c                    | j                   | S t               }|j                  |j                  |t        z         |r| j                  |      }|S | j                  t        t        |                  }|S )ad  rotate a copy

        Rotates a shape around an axis.

        Args:
            axis (Axis): rotation Axis
            angle (float): angle to rotate, in degrees
            transform (bool): regenerate the shape instead of just changing its location.
                Defaults to False.

        Returns:
            a copy of the shape, rotated
        )	r   rD   SetRotationr   rh   rp  r  rn   rQ   )r   r9  angle	transformrr  rotated_selfs         r   rotatezShape.rotate'  sm     == K ""4<<A00@L   ::h~/N&OPLr   c           
        | j                   }|J ||j                  n
t        |      }t        |t        t
        f      rDt               }|j                  |j                         t        |             | j                  |      S t        |t              rt        |      dk(  rt        d |D              rt        |      }t        |j                  dd|j                  d|j                  z
  z  gd|j                  d|j                  d|j                  z
  z  gdd|j                   |j                   d|j                   z
  z  gg dg      }| j#                  |      S t%        d      )a'  Scale this shape about a point.

        Non-uniform scaling may change the underlying geometry type to splines.
        When ``about`` isn't provided, the shape is scaled about its location.

        Args:
            factor (float | tuple[float, float, float]): uniform scale factor or
                three scale factors for the X, Y and Z directions.
            about (VectorLike, optional): point to scale about. Defaults to the
                shape's location position.

        Returns:
            Shape: a copy of the scaled shape.
        r   c              3  H   K   | ]  }t        |t        t        f        y wr   )r   intfloat)r7  scales     r   r8  zShape.scale.<locals>.<genexpr>`  s     HJusEl3H    "r   rx   )r   r   r   r\  z0factor must be a float or a three tuple of float)r   r   rs   r   r  r  rD   SetScaler5  rp  r  r?  r  ro   r  r  r  transform_geometryr   )r   factoraboutcurrent_locationabout_pointrr  scale_vectorscale_matrixs           r   r  zShape.scaleA  sN   (  ==+++38=&//fUmfsEl+$YN##K$6$6$8%-H((88vu%Fq HHH!&>L! %#\^^);<	 $#\^^);<	 $#\^^);<	 )'L. **<88OPPr   c                .    t         j                  | d      S )Return the Shellr~   r  r   s    r   shellzShape.shell~      %%dG44r   c                .    t         j                  | d      S )z%shells - all the shells in this Shaper~   r+  r   s    r   shellszShape.shells      ##D'22r   c                f   | j                   Dt        | j                   t              r*| j                  r|dn|}t        j                  | |      }|S t        j                  t        t        | j                         g t        j                  |         }|dn|}t        j                  |d   |      }|S )u  Display internal topology

        Display the internal structure of a Compound 'assembly' or Shape. Example:

        .. code::

            >>> c1.show_topology()

            c1 is the root         Compound at 0x7f4a4cafafa0, Location(...))
            ├──                    Solid    at 0x7f4a4cafafd0, Location(...))
            ├── c2 is 1st compound Compound at 0x7f4a4cafaee0, Location(...))
            │   ├──                Solid    at 0x7f4a4cafad00, Location(...))
            │   └──                Solid    at 0x7f4a11a52790, Location(...))
            └── c3 is 2nd          Compound at 0x7f4a4cafad60, Location(...))
                ├──                Solid    at 0x7f4a11a52700, Location(...))
                └──                Solid    at 0x7f4a11a58550, Location(...))

        Args:
            limit_class: type of displayed leaf node. Defaults to 'Vertex'.
            show_center (bool, optional): If None, shows the Location of Compound 'assemblies'
                and the bounding box center of Shapes. True or False forces the display.
                Defaults to None.

        Returns:
            str: tree representation of internal structure
        F)r)  r*  Tr   )
r   r   rT   r   r   rV  r'  r   rX   inverse_shape_LUT)r   limit_classr+  rQ  r)  s        r   show_topologyzShape.show_topology  s    D LL$4<<9#.#6%KK%%dK8F  $$lDLL1--k: % D
 #."5$;K%%d1g{;Fr   c                .    t         j                  | d      S )Return the Solidr|   r  r   s    r   solidzShape.solid  r  r   c                .    t         j                  | d      S )z%solids - all the solids in this Shaper|   r+  r   s    r   solidszShape.solids  r  r   c                     y)z split and keep inside or outsideNr   r   toolkeeps      r   splitzShape.split  r   r   c                     y)z%split and return the unordered piecesNr   r  s      r   r  zShape.split  r   r   c                     y)z!split and keep inside and outsideNr   r  s      r   r  zShape.split  r   r   c                     y)zinvalid splitNr   r  s      r   r  zShape.split  r   r   c                     y)zsplit and keep inside (default)Nr   )r   r  s     r   r  zShape.split  r   r   c                     j                   |st        d      |t        j                  t        j                  fv rt        | d      t               }|j                   j                         t        |t              r#t        |j                        j                         n|j                  }t               }|j                  |       t               }|j                  |       |j                  |       |j                          t!        |j#                               }t        |t$              rt'        |d      }|t        j(                  k(  rt+         fdt-        |      D              S t        |t              s&t        |t.              r>t1        |t2        j4                        }t7        j                  |j9                               }	n|}	t;               }
t=               }t?        j@                  |	      \  }}}}tC        |	      jE                  ||z   dz  ||z   dz  |
|       tG        |jI                         |jK                         |jM                               jO                         }tG        |
      }||z   }tQ        ||jS                               }|jU                         }g }g }tW               }t-        |      D ]  } jX                  j[                  |      }t        |t              r-|j]                  |      j_                         jL                  dk\  }nDta        |fftc                     }te        jf                  ||       |ji                         tj        k\  }|r|n|jm                  |        |sdnto        |      dk(  r|d   n|}|sdnto        |      dk(  r|d   n|}|t        jp                  k(  r||fS |t        jr                  k(  r|S |t        jt                  k(  r|S y)	aH  split

        Split this shape by the provided plane or face.

        Args:
            surface (Plane | Face): surface to segment shape
            keep (Keep, optional): which object(s) to save. Defaults to Keep.TOP.

        Returns:
            Shape: result of split
        Returns:
            Self | list[Self] | None,
            Tuple[Self | list[Self] | None]: The result of the split operation.

            - **Keep.TOP**: Returns the top as a `Self` or `list[Self]`, or `None`
              if no top is found.
            - **Keep.BOTTOM**: Returns the bottom as a `Self` or `list[Self]`, or `None`
              if no bottom is found.
            - **Keep.BOTH**: Returns a tuple `(inside, outside)` where each element is
              either a `Self` or `list[Self]`, or `None` if no corresponding part is found.
        Nz#Can't split an empty edge/wire/toolz is invalidTc              3  T   K   | ]  }j                   j                  |       ! y wr   rM  )r7  partr   s     r   r8  zShape.split.<locals>.<genexpr>  s(       ##D)rN  r   r   rx   );r   r   re   INSIDEOUTSIDEr^   Appendr   r   rr   r,   r}   r)   SetArgumentsSetToolsr  r   r   rT   unwrap_topods_compoundALLrz  r   rY   rP   r   r   rR   CurrentrC   rE   r;   
UVBounds_sr7   Normalrs   r  r  r  
normalizedr:   r5  r|   rG   rG  r   to_local_coordsr!  _topods_bool_opr%   r6   LinearProperties_sr   ri   r   r?  BOTHTOPBOTTOM)r   r  r  r|  	trim_tool	tool_listsplittersplit_resultface_explorer	tool_facesurface_gppntr  u_minu_maxv_minv_maxnormalized_surface_normalr  	ref_pointhalf_space_maker
tool_solidtopsbottomsr   r  	sub_shapeis_up	is_up_objtopbottoms   `                             r   r  zShape.split  sd   , == BCCDKK..v[122)+
$,,'
 $& $DLL1668 	
 )*	# () 	j))$ 	 01lO41,EL 488 7E  
 $&)\2 /	2>> J"KK(=(=(?@	%	 #HM#XN)2)=)=i)H&E5%9%,,!#eemq%8- )/  "N$4$4$68H8H8J)jl & #=1M%(AAI
  9IDTDTDVW)//1J!!^
/= 	;D++D1I$&,,Y7>>@BBaG ,Gj],>,@	 ,,Y
C")Y6T//	:	; ds4yA~DG4$G8I'!*w499= 488J4;;M r   c                     y)z-split_by_perimeter and keep inside or outsideNr   r   	perimeterr  s      r   split_by_perimeterzShape.split_by_perimeterR  r   r   c                     y)z.split_by_perimeter and keep inside and outsideNr   r  s      r   r  zShape.split_by_perimeterX  r   r   c                     y)z,split_by_perimeter and keep inside (default)Nr   r  s      r   r  zShape.split_by_perimetera  r   r   zhShape.split_by_perimeter is deprecated; use Face.split_by_perimeter or Shell.split_by_perimeter instead.c                B    d	 fd} fd}|t         j                  t         j                  t         j                  hvrt	        d       j
                  t	        d      |j                  st	        d      t               }|j                         D ]   }|s|j                  |j                         " g }g } j                         }	|	s j                         }	|	D ]  }
|
st        |
j                        }|j                  |       |j                          |j!                   ||j#                                      |j!                   ||j%                                        ||      } ||      }|j&                  }|r t)        d |j                         D              nd}|r t)        d |j                         D              nd}t+        ||z
        t+        ||z
        k  }|t         j                  k(  r
|r||fS ||fS |t         j                  k(  r|r|S |S |r|S |S )
aa  split_by_perimeter

        Divide the faces of this object into those within the perimeter
        and those outside the perimeter.

        Note: this method may fail if the perimeter intersects shape edges.

        Args:
            perimeter (Union[Edge,Wire]): closed perimeter
            keep (Keep, optional): which object(s) to return. Defaults to Keep.INSIDE.

        Raises:
            ValueError: perimeter must be closed
            ValueError: keep must be one of Keep.INSIDE|OUTSIDE|BOTH

        Returns:
            Union[Face | Shell | ShapeList[Face] | None,
            Tuple[Face | Shell | ShapeList[Face] | None]: The result of the split operation.

            - **Keep.INSIDE**: Returns the inside part as a `Shell` or `Face`, or `None`
              if no inside part is found.
            - **Keep.OUTSIDE**: Returns the outside part as a `Shell` or `Face`, or `None`
              if no outside part is found.
            - **Keep.BOTH**: Returns a tuple `(inside, outside)` where each element is
              either a `Shell`, `Face`, or `None` if no corresponding part is found.

        c                    g }t        | j                               D ]\  }| j                         }|j                         s*|j	                  j
                  j                  |             | j                          ^ |S )z0Return objects from TopTools_ListOfShape as list)r   SizeFirstr   r   rG  r   RemoveFirst)losr  _firstr   s       r   r  z%Shape.split_by_perimeter.<locals>.get  sb    F388:& "		||~MM$.."5"5e"<=!	"
 Mr   c                    | syt        |       dk(  r| d   S t        | D cg c]  }|j                   c}      }t        |t              rj
                  j                  |      S t        |       S c c}w )zgProcess sides to determine if it should be None, a single element,
            a Shell, or a ShapeList.Nrx   r   )r?  _sew_topods_facesr   r   rY   rG  r   rz  )sidesr  potential_shellr   s      r   process_sidesz/Shape.split_by_perimeter.<locals>.process_sides  sh     5zQQx/E0Jq0JKO/<8~~**?;;U## 1Ks   A1z;keep must be one of Keep.INSIDE, Keep.OUTSIDE, or Keep.BOTHzCannot split an empty shapez'perimeter must be a closed Wire or Edgec              3  4   K   | ]  }|j                     y wr   r~  r7  r  s     r   r8  z+Shape.split_by_perimeter.<locals>.<genexpr>  s     #CAHH#C   r   c              3  4   K   | ]  }|j                     y wr   r  r  s     r   r8  z+Shape.split_by_perimeter.<locals>.<genexpr>  s     $E!QXX$Er  )r  r^   returnr@  )re   r  r  r  r   r   	is_closedr_   r#  r  r   r  r,  r5   Addr  rS  LeftRightr~  r^  r7  )r   r  r  r  r  perimeter_edgesperimeter_edgeleftsrightstarget_shapestarget_shapeconstructorleftrightperimeter_lengthleft_perimeter_lengthright_perimeter_lengthleft_insides   `                 r   r  zShape.split_by_perimeterg  s   B		$ T\\499==M  == :;; ""FGG24'oo/ 	;N!"">#9#9:	; %'%' JJLM) 	4L-l.B.BCKOOO,LL[--/01MM#k//123	4 U#f% %++GK#Cdjjl#C CQRIN$Eu{{}$E!ETU*-BBCc55G
 
 499$/D%=BeT]B4;;&41E1#u--r   c                   | j                   t        d      | j                  ||       g }g }d}| j                         D ]  }|j                  J t               }t        j                  |j                  |      |j                         |j                  j                         t        j                  k(  }|fdt        dj                         dz         D        D 	cg c]9  }	t        |	j                         |	j!                         |	j#                               ; c}	z  }|j%                         D 
cg c]  }
|rD|
j'                  d      |z   dz
  |
j'                  d      |z   dz
  |
j'                  d      |z   dz
  fnC|
j'                  d      |z   dz
  |
j'                  d      |z   dz
  |
j'                  d      |z   dz
  f c}
z  }|j                         z  } ||fS c c}	w c c}
w )z"General triangulated approximationz Cannot tessellate an empty shaper   c              3  ^   K   | ]$  }j                  |      j                         & y wr   )NodeTransformed)r7  r   polyr  s     r   r8  z#Shape.tessellate.<locals>.<genexpr>  s)      78DIIaL,,T2s   *-rx   r   r   )r   r   ri  r,  r   rQ   r!   rg  r  OrientationrM   TopAbs_REVERSEDr   NbNodesrs   r  r  r  	Trianglesr   )r   r  rh  vertices	trianglesoffsetr)  r   r   vtr'  r  s              @@r   
tessellatezShape.tessellate  s    == ?@@		)./!#02	JJL  	%D<<+++!#C,,T\\3?D%%'Dll..04F4V4VVG <A!T\\^VWEW<X qssuacceQSSU+ H  )  	 
V+a/
V+a/
V+a/ 
V+a/
V+a/
V+a/
 I" dlln$FA 	%D ""5s   #>G)9BG.c                   | j                   t        d      t               }t        j                  | j
                  |||dt        j                  t        j                  d| |
      }| j                  j                  |      S )aU  to_splines

        A shape-processing utility that forces all geometry in a shape to be converted into
        BSplines. It's useful when working with tools or export formats that require uniform
        geometry, or for downstream processing that only understands BSpline representations.

        Args:
            degree (int, optional): Maximum degree. Defaults to 3.
            tolerance (float, optional): Approximation tolerance. Defaults to 1e-3.
            nurbs (bool, optional): Use rational splines. Defaults to False.

        Returns:
            Self: Approximated shape
        z!Cannot approximate an empty shaperx   T)
r   r   rJ   rI   BSplineRestriction_sr   ga
GeomAbs_C0rG  r   )r   degreer  nurbsparamsrQ  s         r   
to_splineszShape.to_splines	  su    " == @AA2411LLMMMMI
 ~~""6**r   c                    | j                   | S t        j                  | d      }t        t	        | j
                  |j
                  d      j                               }t        t        |      |_        |S )a[  Apply affine transform

        WARNING: transform_geometry will sometimes convert lines and circles to
        splines, but it also has the ability to handle skew and stretching
        transformations.

        If your transformation is only translation and rotation, it is safer to
        use :py:meth:`transform_shape`, which doesn't change the underlying type
        of the geometry, but cannot handle skew transformations.

        Args:
            t_matrix (Matrix): affine transformation matrix

        Returns:
            Shape: a copy of the object, but with geometry transformed
        NT)	r   r  r  r   r+   r   r   r   r   r   t_matrixr  transformeds       r   r  zShape.transform_geometry&	  sc    " == KMM$-	%dllH4D4DdKQQS
 "&+6	r   c                   | j                   | S t        j                  | d      }t        t	        | j
                  |j
                  j                               j                               }t        t        |      |_        |S )a  Apply affine transform without changing type

        Transforms a copy of this Shape by the provided 3D affine transformation matrix.
        Note that not all transformation are supported - primarily designed for translation
        and rotation.  See :transform_geometry: for more comprehensive transformations.

        Args:
            t_matrix (Matrix): affine transformation matrix

        Returns:
            Shape: copy of transformed shape with all objects keeping their type
        N)
r   r  r  r   r1   r   Trsfr   r   r   r;  s       r   transform_shapezShape.transform_shapeA	  sj     == KMM$-	$T\\83C3C3H3H3JKQQS
 "&+6	r   c           
     r   t        |      j                  t              }t               }|j	                  t        t        ddd      t        ddd            |j                         t               }|j	                  t        t        ddd      t        ddd            |j                         t               }|j	                  t        t        ddd      t        ddd            |j                         t               }|j                  t        |      j                         | j                  ||z  |z  |z        S )a  Transform Shape

        Rotate and translate the Shape by the three angles (in degrees) and offset.

        Args:
            rotate (VectorLike, optional): 3-tuple of angles to rotate, in degrees.
                Defaults to (0, 0, 0).
            offset (VectorLike, optional): 3-tuple to offset. Defaults to (0, 0, 0).

        Returns:
            Shape: transformed object

        r   rx   )rs   r_  rh   rD   r  r?   rC   rB   r  r  r  SetTranslationr   rp  )r   r  r.  rotate_vectort_rxt_ryt_rzt_os           r   r=  zShape.transformedX	  s    " v//8yq!Q1aA=??Syq!Q1aA=??Syq!Q1aA=??Si6&>112$$S4Z$%6%=>>r   c                    | j                   | S t               }|j                  t        |      j                         |r| j                  |      }|S | j                  t        t        |                  }|S )a?  Translates this shape through a transformation.

        Args:
            vector (VectorLike): relative movement vector
            transform (bool): regenerate the shape instead of just changing its location
                Defaults to False.

        Returns:
            object with a relative move applied
        )	r   rD   rB  rs   r   rp  r  rn   rQ   )r   vectorr  rr  self_translateds        r   	translatezShape.translateu	  sm     == K %%fVn&<&<="33NCO  #jj/.2Q)RSOr   c                .    t         j                  | d      S )Return the Wirer{   r  r   s    r   wirez
Shape.wire	  r  r   c                .    t         j                  | d      S )z#wires - all the wires in this Shaper{   r+  r   s    r   wireszShape.wires	  r-  r   c                    | j                   | S t        j                  | d      }t        | j                  |d      j                         }t        t        t        |            |_        |S )zPrivate Apply Transform

        Apply the provided transformation matrix to a copy of Shape

        Args:
            transformation (gp_Trsf): transformation matrix

        Returns:
            Shape: copy of transformed Shape
        NT)	r   r  r  r1   r   r   r   r   r   )r   rr  rB  transformed_shapes       r   rp  zShape._apply_transform	  sc     == K MM$5
4LL
 %'	 	
 #684E+FG
r   c                   t        |      }t        |      }| g|z   |z   D ci c]6  }t        t        |      d      rt        |      t        |      j                  8 }}t	        |j                         d       d   t        |t         t        f      r|d   n|}t               }|D ]*  }|j                  |j                  |j                         , t               }	|D ]*  }|j                  |	j                  |j                         , d}
t        |t              rA|	j                         r |j                         dk(  r|j                         }
nt        |      }
nt        |t               r|	j                         r0|j                         dk(  r|j                         }
nt        |      }
n|j                         rp|	j                         dk(  r|	j                         }
nLt        |	      }
n@t        |t"              r0|	j                         s|j                         r| j%                         S |
\|j'                  |       |j)                  |	       |j+                  d       |j-                          t/        |j1                               }
t2        j4                  rIt7        |
ddd      }|j9                  d	       	 |j-                          t/        |j1                               }
t        |
t@              rtC        |
d      }
t        |
t@              rod   dk7  rgtE        fdtG        |
      D              }|D ]  }|jI                  |ddg        t0        jK                  |d         }|jI                  |ddg       |S d   jM                  |
      }|jI                  |ddg       |S c c}w # t:        $ r t=        j>                  d
d       Y w xY w)a  Generic boolean operation

        Args:
          args: Iterable[Shape]:
          tools: Iterable[Shape]:
          operation: Union[BRepAlgoAPI_BooleanOperation:
          BRepAlgoAPI_Splitter]:

        Returns:
            Shape or Compound result

        orderc                    | d   S r0  r   )r}  s    r   r   z Shape._bool_op.<locals>.<lambda>	  s
    DG r   r2  r  r   Nrx   TFz!Boolean operation unable to cleanr   r  r5  c              3  F   K   | ]  }d    j                  |        yw)r   Nr   )r7  r  highest_orders     r   r8  z!Shape._bool_op.<locals>.<genexpr>
  s)        a %%a( s   !r   _NodeMixin__children)'r@  rF  r  rT  sortedr  r   r  r^   r   r  r&   IsEmptyr   r  !_make_topods_compound_from_shapesr'   r%   rG  r  r  SetRunParallelr  r   r   r  r  rL   r  r  r  r  rT   r  rz  r   r   r  r   )r   argstools	operationr  
order_dictbaseargr   r  topo_resultr  resultsrQ  rW  s                 @r   r  zShape._bool_op	  sU   $ DzU Vd]U*
tAw( GT!W]]"

 

 z//17KLRP %TD%=9tAwt"$ 	)C||'

3<<(	) $% 	*C||'CLL)	*
 i1||~::<1$"%))+K"CC"HK	#34||~::<1$"%))+K"CC"HK;;=A%"&**,K"CD"IK	#56||~~~''""3't$$$T*OO"9??#45K ??3KtTRH''.Q &x~~'78
 k?30dCKk?3a8HA8M  4[A  G " U''<R0STU))'=3CDF##FY8N,OPMq!&&{34J(KLa
v  QAaPQs   ;N-?)N2 2 OOc                    | j                  |||      }|j                  r
t               S t        |j                  t
              r|j                         S t        |g      S )a  Generic boolean operation that always returns ShapeList.

        Wrapper around _bool_op that guarantees ShapeList return type,
        wrapping single results and returning empty ShapeList for null results.

        Args:
          args: Iterable[Shape]:
          tools: Iterable[Shape]:
          operation: Union[BRepAlgoAPI_BooleanOperation, BRepAlgoAPI_Splitter]:

        Returns:
            ShapeList (possibly empty)

        )r  r   rz  r   r   rT   r  )r   r]  r^  r_  rQ  s        r   _bool_op_listzShape._bool_op_list
  sO    ( tUI6>>;fnno6..00&""r   c                   | j                   |st               t               fS t        | j                  |j                        }|j	                  d       |j                  d       |j                  d       |j                  d       |j                          |j                         }g }t        |t        j                        }|j                         rb|j                  | j                  j!                  t#        |j%                                            |j'                          |j                         rbt               }t        |t        j(                        }|j                         rb|j                  | j                  j!                  t#        |j%                                            |j'                          |j                         rbt        t+        |            |fS )a  _ocp_section

        Create a BRepAlgoAPI_Section object

        The algorithm is to build a Section operation between arguments and tools.
        The result of Section operation consists of vertices and edges. The result
        of Section operation contains:
        - new vertices that are subjects of V/V, E/E, E/F, F/F interferences
        - vertices that are subjects of V/E, V/F interferences
        - new edges that are subjects of F/F interferences
        - edges that are Common Blocks


        Args:
            other (Union[Vertex, Edge, Wire, Face]): shape to section with

        Returns:
            tuple[ShapeList[Vertex], ShapeList[Edge]]: section results
        T)r   rz  r(   r   r\  ApproximationComputePCurveOn1ComputePCurveOn2r  r   rP   rN   TopAbs_VERTEXr$  r   rG  r   r   r  r(  r   r  )r   r  sectionintersection_shaper,  explorerr#  s          r   _ocp_sectionzShape._ocp_section,
  sZ   , == K--%dllEMMBt$d#  &  & ,3==?!#"#57G7U7UVmmoOODNN//9I9I9K0LMNMMO mmo "+"#57G7S7STmmoLL,,Xh6F6F6H-IJKMMO mmo #h-(%00r   c                X    ddl m}m} |r ||       j                         S t	        |       S )z!Jupyter 3D representation supportr   )shape_to_htmlhas_vtk)build123d.jupyter_toolsrq  rr  _repr_html_rH  )r   rq  rr  s      r   rt  zShape._repr_html_]
  s)     	C &2244Dzr   c                .    t         j                  | d      S )Return the Vertexr   r  r   s    r   vertexzShape.vertexf
  s    %%dH55r   c                .    t         j                  | d      S )z)vertices - all the vertices in this Shaper   r+  r   s    r   r,  zShape.verticesj
  s    ##D(33r   )Nr   NN)r   TopoDS_Shape | Noner   r   r   ColorLike | Noner   zCompound | None)r   r   )r  r   r  r  )r  zNone | Color)r   rz  r  None)r  rd   )r  boolr  rn   )r   rn   )r  zlist[list[float]]r  rs   )r  rt   )r   rt   )r  zlist[tuple[Vector, float]])r  r  )r  ztuple[float, float, float])r  z
type[Self]r   rX   r  ra   )r   r   r  rt   r  z&Edge | Face | Shell | Solid | Compound)r   rX   r)  list[_DisplayNode]r   z_DisplayNode | Noner*  rN   r+  r}  r  r  )r+  r}  r  r   )rb  Iterable[Shape]rc  rc   r  rs   )r   r   r  r  )r   r   ro  Literal['Vertex']r  ShapeList[Vertex])r   r   ro  Literal['Edge']r  ShapeList[Edge])r   r   ro  Literal['Wire']r  ShapeList[Wire])r   r   ro  Literal['Face']r  ShapeList[Face])r   r   ro  Literal['Shell']r  ShapeList[Shell])r   r   ro  Literal['Solid']r  ShapeList[Solid])r   r   ro  Literal['Compound']r  ShapeList[Compound])r   r   ro  GLiteral['Vertex', 'Edge', 'Wire', 'Face', 'Shell', 'Solid', 'Compound']r  rz  )r   r   ro  r  r  r   )r   r   ro  r  r  rz   )r   r   ro  r  r  r{   )r   r   ro  r  r  r}   )r   r   ro  r  r  r~   )r   r   ro  r  r  r|   )r   r   ro  r  r  ry   )r   r   ro  r  r  r   )r  r   r  CompositeFactoryr  r|  r   )r  r  r  r   r  r   )r  r|  r  ra   )r  Shape | Iterable[Shape]r  Self | Compound)r  r  r  zNone | Self | Compound)r  ra   )r  r  )r  zPlane | Locationr  ra   )r  zIterable[Plane | Location]r  
list[Self])r  z-Plane | Location | Iterable[Plane | Location]NT)r  float | Noner  r}  r  rk   )r  Shape | VectorLiker  ztuple[Vector, Vector]r  ry   r  r  )r  r   r  zIterable[str] | None)r  r   r  r  )r  r   r  r  )r  r  r  r  )r  r  r  ztuple[float, Vector, Vector])r  r   r  zIterator[float]r  rz   r  r  )r&  r  r  list[TopoDS_Shape]r  r}   r  r  )g-C6?)r9  rj   r:  r  r  r  )rH  r   rC  r}  r:  r  r  r  )r  zShapeList[Shape])rU  (Shape | Vector | Location | Axis | Planer  r  rP  r}  r  ShapeList | None)rO  F)r  r  r  r  rP  r}  r  r  )rO  )r  r   r  r  r  rz  )r  r   r  r}  )r   rn   r  ra   )g?)r  r  rh  r  )rq  zPlane | Noner  ra   )r   zLocation | Planer  ra   )r  rq   )r   )r,  zlist[Face] | Compoundr   zWire | Edger  r  r  r  )r9  rj   r  r  )r   rn   F)r9  rj   r  r  r  r}  r  ra   )r  z"float | tuple[float, float, float]r  zVectorLike | Noner  ra   r  r~   r  r  )r   N)r  zGLiteral['Compound', 'Edge', 'Face', 'Shell', 'Solid', 'Vertex', 'Wire']r+  zbool | Noner  r   r  r|   r  r  )r  TrimmingToolr  zLiteral[Keep.TOP, Keep.BOTTOM]r  Self | list[Self] | None)r  r  r  zLiteral[Keep.ALL]r  r  )r  r  r  Literal[Keep.BOTH]r  z9tuple[Self | list[Self] | None, Self | list[Self] | None])r  r  r  "Literal[Keep.INSIDE, Keep.OUTSIDE]r  r|  )r  r  r  r  )r  r  r  re   )r  Edge | Wirer  r  r  %Face | Shell | ShapeList[Face] | None)r  r  r  r  r  zStuple[Face | Shell | ShapeList[Face] | None, Face | Shell | ShapeList[Face] | None])r  r  r  zLiteral[Keep.INSIDE]r  r  )r  r  r  re   )r  r  rh  r  r  z/tuple[list[Vector], list[tuple[int, int, int]]])r   gMbP?F)r6  r  r  r  r7  r}  r  ra   )r<  ro   r  ra   )r   r   r   r  )r  rt   r.  rt   r  ra   )rI  rt   r  r}  r  ra   r  r{   r  r  )rr  rD   r  ra   )r]  r  r^  r  r_  3BRepAlgoAPI_BooleanOperation | BRepAlgoAPI_Splitterr  r  )r]  r  r^  r  r_  r  r  rz  )r   r   r  zVertex | Edge | Wire | Facer  z)tuple[ShapeList[Vertex], ShapeList[Edge]]r  r   r  r  )r   r   r   r   r   __annotations__r   rk  r   TopAbs_WIREr   TopAbs_SHELLTopAbs_SOLIDTopAbs_COMPOUNDTopAbs_COMPSOLIDr  r6   r  r   r   r   r  r  rR   r   rz   r{   r}   r~   r|   ry   r   downcast_LUTr4  GeomAbs_Linerd   LINEGeomAbs_CircleCIRCLEGeomAbs_EllipseELLIPSEGeomAbs_Hyperbola	HYPERBOLAGeomAbs_ParabolaPARABOLAGeomAbs_BezierCurveBEZIERGeomAbs_BSplineCurveBSPLINEGeomAbs_OffsetCurveOFFSETGeomAbs_OtherCurver   r   GeomAbs_PlanePLANEGeomAbs_CylinderCYLINDERGeomAbs_ConeCONEGeomAbs_SphereSPHEREGeomAbs_TorusTORUSGeomAbs_BezierSurfaceGeomAbs_BSplineSurfaceGeomAbs_SurfaceOfRevolution
REVOLUTIONGeomAbs_SurfaceOfExtrusion	EXTRUSIONGeomAbs_OffsetSurfaceGeomAbs_OtherSurfacer   rg   TRANSFORMEDr2   ROUNDr/   RIGHTr.   _transModeDictr   r   rN   r%  r   propertyr   setterr   r   r   r   r   r   r   r   rb   r   r   r   r   r  r  r   r  r  r  classmethodr   r  staticmethodr'  rV  rc   r]  ri  rY  r   rp  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{  r)  r,  r?  rA  r  r  r  rR  rZ  r]  r  rb  re  ri  rs  rw  r  r{  r  r  r  r  r  r  r  r  r  r  r  re   r  r  r  r1  r9  r  r@  r=  rK  rN  rP  rp  r  rf  ro  rt  rw  r,  )r7  kr/  s   000r   r   r      s   ( IKEJ 	(





J
[	I 	$
	44
	44
	55
66
55
I88
Y99	C? 	 +4//*;<<$!QA< 	&--





FOO
V--	L 	
8??
H,,
h00
X..

!1!1

x~~
;M7 
 	(..
X..

8??
(..
  (//
!!8#3#3
&&(;(;
%%x'9'9
  (//
=M9  	 :44N ,y ," 	(())%%%%$$$$$$&&	O $("&"&. . .  	.
  .0  
 ^^ ) &  & ! !  $ \\B B  2 5 5n > > 	()	 
) 	 	 N N  1 1 __1 1
 ) )V ) )     & & __    
 
: G G * *< E  E $.	/  2  '+"2"@"@   $  	
  
 8 & &P 8@+ +-5+	+ +Z ! !,   #4 	     #2	   #2	   #2	   #3	   #3	   ""#6"	"  " 

 
   U  UQ  QQ  QQ  QS  SS  S#6	   

 
 * 5"5-=5	5 5 >B#$#1;#	# #  / /M M!F$&("" < <L L
 / /M M&R ?CY%Y7;Y	Y,(@8
 AE;;)=;>6O>
'
	%
2$.4
942 *H*H *H 
	*HX
 -2t%)8D	f
6   %	.2?.2 .2 	.2
 
.2h   %	7  	
 
*"32"$5, && 	E*$E* E* 	E*
 
E*N 9D/:: $(;Q2;Q !;Q 
	;Qz53 #'0
0
 !0 
0d53 / /(F/	!/ /
 4 4 0 0  (J	 
 . . 6:XX un <$<,N<	.< <
 =$=,>=
= = CG;;;$;,@;	.; ;
 	/ GKkk c.	c.L <?/#/#38/#	8/#d GL#+#+*/#+?C#+	#+J60 DM? ?6@?	?:.42,ee e G	e
 
eN## # G	#
 
#6/1/17/1	2/1b64]L =s   2e8c                  4    e Zd ZdZedd       Zedd       Zy)
Comparablez4Abstract base class that requires comparison methodsc                     y r   r   r  s     r   r  zComparable.__eq__t
      *-r   c                     y r   r   r  s     r   __lt__zComparable.__lt__w
  r  r   Nr  r   r  r}  )r   r   r   r   r   r  r  r   r   r   r  r  o
  s#    > - -- -r   r  c                      e Zd ZdZddZy)SupportsLessThanzShapeList comparison criteriac                     y r   r   r  s     r   r  zSupportsLessThan.__lt__~
  r   r   Nr  )r   r   r   r   r  r   r   r   r  r  {
  s    '-r   r  TKc                  n    e Zd ZdZdd	 	 	 	 	 ddZddZd Zd Zd Zd	 Z	dd
Z
ddZ	 d	 	 	 	 	 ddZy)GroupByzKResult of a Shape.groupby operation. Groups can be accessed by index or keyFr  c          	        g | _         g | _        || _        t        t	        j
                  t        |||      |            D ]I  \  }\  }}| j                  j                  t        |             | j                   j                  ||f       K y )Nr  r   r2  )	key_to_group_indexgroupskey_frC  	itertoolsgroupbyrY  r   rz  )r   r  	shapelistr   r   r  
shapegroups          r   r   zGroupBy.__init__
  s     8:*,
$-fYE7KQVW%
 	5 A Z KKy45##**C84		5r   c                     | j                   |   S r   )r  r   r  s     r   __getitem__zGroupBy.__getitem__
  s    {{3r   c                ,    t        | j                        S r   )iterr  r   s    r   __iter__zGroupBy.__iter__
  s    DKK  r   c                ,    t        | j                        S r   )r?  r  r   s    r   __len__zGroupBy.__len__
  s    4;;r   c                *    t        t        |             S r   )rH  rz  r   s    r   __repr__zGroupBy.__repr__
  s    IdO$$r   c                    t        |       S r   )r   r   s    r   __str__zGroupBy.__str__
  s    d|r   c                l    | j                   D ]  \  }}||k(  s| j                  |   c S  t        |      )zSelect group by key)r  r  KeyError)r   r  r  r   s       r   groupzGroupBy.group
  s<    ++ 	&DAqax{{1~%	& smr   c                B    | j                  | j                  |            S )zSelect group by shape)r
  r  r   s     r   	group_forzGroupBy.group_for
  s    zz$**U+,,r   c                   |r|j                  d       y|j                  ddd      5  t        |       D ]9  \  }}|r!|j                  d       |j                          |j	                  |       ; 	 ddd       y# 1 sw Y   yxY w)aS  
        Render a formatted representation of the object for pretty-printing in
        interactive environments.

        Args:
            printer (PrettyPrinter): The pretty printer instance handling the output.
            cycle (bool): Indicates if a reference cycle is detected to
                prevent infinite recursion.
        z(...)rx   [],N)textr
  rC  	breakabler   )r   printercycleidxr}  s        r   _repr_pretty_zGroupBy._repr_pretty_
  sv     LL!q#s+ )!*4 )ICS)))+NN4(	)) ) )s   AA::BN)r  zCallable[[T], K]r  zIterable[T]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  r
  r  r  r   r   r   r  r  
  sq    U 55 5
 5( ! %-
 =B),)59)	)r   r  c           	     v	  !"# t        | t              rt        | g      n
t        |       }|st        d      t	        d |D              st        d      |d   j
                  #t        #fd|D              rt        d      ddd	d
ddd}t        j                  t        j                  t        j                  t        j                  t        j                  d}#|vrt        d#       |D cg c]  }|j                   }}t        d |D              rt        d      t        t        t           |      }|d   "t        "fd|dd D              rt        d      t        t        t            t        "|#                      }t               }|D 	ci c]"  }	|	j                    ||	j                         |	$ }
}	#dk(  rS|D 	ci c]  }	|	t#                }}	t%               }t'        j(                  "j                   t        j                  t        j                  |       t+        |j-                               D ]  }t/        j0                  |j3                  |dz               }|
j5                   ||            }|D|j7                  |      D ]  }t/        j8                  |      }t;               }t;               }t'        j<                  |||       ||fD ]6  }|
j5                   ||            }|||k7  s#||   j?                  |       8   nt%               }t'        j(                  "j                   |#   t        j@                  #   |       |D 	ci c]  }	|	g  }}	i }t+        |j-                               D ]r  }|j3                  |dz         }g }|j7                  |      D ]A  }|
j5                   ||            }	|	|jC                  |	       ||	   jC                  |       C |||<   t i !tE               }|D ]"  }||v s|!vsd!|<   |jC                  |       $ |ri|jG                         }#dk(  r|   }n#|   D 	ch c]  }|   D ]	  }	|	|k7  r|	  }}}	|D ]#  }|!v r!|   dz   !|<   |jC                  |       % |rid!"#fd} | S c c}w c c}	w c c}	w c c}	w c c}	}w )a  Return a key function that yields topological distance to ``other``.

    The returned callable is intended for use with :meth:`ShapeList.sort_by`
    and :meth:`ShapeList.group_by`. Distances are measured on the full topology
    of the shared ``topo_parent`` of the reference shape(s), not only within
    the ``ShapeList`` being sorted or grouped.

    The first-pass implementation supports homogeneous collections of:
    ``Vertex``, ``Edge``, ``Wire``, ``Face``, ``Shell``, and ``Solid``.

    Adjacency is defined by shared lower-order topology:
    - ``Face`` via shared ``Edge``
    - ``Edge``/``Wire`` via shared ``Vertex``
    - ``Shell``/``Solid`` via shared ``Face``
    - ``Vertex`` via shared ``Edge``

    Reference shapes have distance ``0``. Directly connected shapes have
    distance ``1``. Each additional intervening peer increases the distance
    by ``1``. Unreachable shapes return ``inf``.

    Args:
        other: reference shape or shapes

    Raises:
        ValueError: empty reference set, mixed shape types, unsupported
            shape type, missing ``topo_parent``, or multiple parents

    Returns:
        Callable[[Shape], int | float]: key function for sorting/grouping
    z6Cannot measure topological distance to an empty objectc              3  <   K   | ]  }t        |t                y wr   )r   r   )r7  r   s     r   r8  z#topo_distance_to.<locals>.<genexpr>
  s     =Ez%'=   +Topological distance requires Shape objectsr   c              3  <   K   | ]  }|j                   k7    y wr   )r  )r7  r   	peer_types     r   r8  z#topo_distance_to.<locals>.<genexpr>
  s     
>U5y(
>r  5Topological distance requires shapes of the same typer,  r#  rP  r,  r  r  )r   rz   r{   r}   r~   r|   )rz   r{   r}   r~   r|   z*Topological distance is not supported for c              3  $   K   | ]  }|d u  
 y wr   r   )r7  r   s     r   r8  z#topo_distance_to.<locals>.<genexpr>  s     
0f6T>
0s   7Topological distance requires shapes with a topo_parentc              3  B   K   | ]  }j                  |         y wr   )r  )r7  	candidater   s     r   r8  z#topo_distance_to.<locals>.<genexpr>  s     
LYv~~i((
Ls   rx   N2Topological distance requires a shared topo_parentr   c                   t        | t              st        d      | j                  k7  rt        d      | j                  t        d      j                  | j                        st        d      j                  | t              }|S )Nr  r  r  r"  )r   r   r   r  r   r  r  r   )r   graph_distancer  r   r  s     r   r  ztopo_distance_to.<locals>.key_fj  sy    #u%JKK>>Y&TUU??"VWW~~coo.QRR"sC0r   )r   r   r  zint | float)$r   r   rz  r   r  r  r  r   rk  r   r   r   r   r@  r  r`   r   r  r]   rO   r   r   r   rR   r   r   r  FindFromKeyrz   r[   r   r`  r  r   r   popleft)$r  sources
plural_lutconnector_enum_lutr   parentsvalid_parentspeersshape_hasherpeerpeer_lookupvertex_neighborsvertex_edge_mapr&  vertex_wrappedvertex_peeredge_wrappedr   r   r   neighbor_wrappedneighborconnector_peer_mappeer_connectorsconnector_to_peers	connectorconnected_peerspeer_wrappedfrontiersourcecurrent	neighborsr  r  r   r  s$                                    @@@r   topo_distance_torA  
  s   B %/ue$<i )EBRGQRR=W==FGG 
%%I

>g
>>PQQ J      
"Ei[QRR.56Uu  6G6

0
00RSS$u+w/M1F

L-:K
LLMNN)E"$JGFJy4I$J$LME*,L5:-1dll>VT\\"D(K  HMR4STT35[4S4SCE&&NNNN		
 ?1134 	DE#]]?+B+B519+MNN%//,~*FGK" / ; ;N K 	D{{<0'/'/!!$9)0'(: D$*|<L/MNH+K0G(599(CD	D	D" GH&&NNy)##I.		
 RW;WD"H;W;W>@-4467 		<E*22519=I O 2 > >y I 8"|L'AB<&&t,%,,Y78 -<y)		< #%I"WH $U?vY6 !IfOOF#$
 ""$ (1I "1!9.y9 7? I  " 	&H9$"+G"4q"8IhOOH%		& $ LK 7
 5TD <X4s$   0R!R&)R&
R+
R0R5c                  ^   e Zd ZdZed*d       Zed*d       Zd+dZd,dZd-dZ	d.dZ
ed/d       Zed0d	       Zd1d
Zej                  fd2dZej                  fd3dZej                  fd2dZd4dZej                  fd5dZej                  fd3dZd-dZd6dZd7dZd8dZd9dZd:dZd;dZd<dZd=dZ	 	 d>	 	 	 	 	 	 	 d?dZ	 d@	 	 	 	 	 	 	 	 	 dAdZej                  ddf	 	 	 	 	 	 	 dBdZ dCdZ!dDd Z"dEd!Z#dFd"Z$ej                  df	 	 	 	 	 dGd#Z%	 dH	 	 	 	 	 dId$Z&dJd%Z'dKd&Z(dLd'Z)dMd(Z*y))Nrz  zGSubclass of list with custom filter and sort methods appropriate to CADc                    | d   S )zFirst element in the ShapeListr   r   r   s    r   r  zShapeList.first  s     Awr   c                    | d   S )zLast element in the ShapeListr  r   r   s    r   lastzShapeList.last  s     Bxr   c                <   t        |t        t        f      r-t        t	        t
        t           t        |       |gz               S t        |t              r2t        d |D              r t        t        |       t        |      z         S t        dt        |       d      )z*Return a new ShapeList that includes otherc              3  H   K   | ]  }t        |t        t        f        y wr   r   r   rs   rZ  s     r   r8  z$ShapeList.__add__.<locals>.<genexpr>  s       /
/0Jq5&/*/
r  Cannot add object of type  to ShapeList)r   rs   r   rz  r   r@  r  r   r  r  r  r  s     r   r  zShapeList.__add__  s    efe_-U47DJ%,@ABBeX&3 /
49/
 ,
 T$Z$u+5664T%[MOPPr   c                
   t        |t        t        f      r!| j                  t	        t
        |             | S t        |t              r%t        d |D              r| j                  |       | S t        dt        |       d      )z#In-place addition to this ShapeListc              3  H   K   | ]  }t        |t        t        f        y wr   rH  rZ  s     r   r8  z%ShapeList.__iadd__.<locals>.<genexpr>  s       1
/0Jq5&/*1
r  rI  rJ  )r   rs   r   r   r   r  r   r  rS  r  r  r  s     r   __iadd__zShapeList.__iadd__  sy    efe_-KKa(  x(S 1
491
 .
 KK  8e]STTr   c                B    t        t        |       t        |      z        S )z#Intersect two ShapeLists operator &rz  r  r  s     r   r  zShapeList.__and__      TSZ/00r   c                \    t        |t              rt        |       t        |      k(  S t        S )zShapeLists equality operator ==r   rz  r  r  r  s     r   r  zShapeList.__eq__  s/     %+ IU#	
  	
r   c                     y r   r   r  s     r   r  zShapeList.__getitem__  s    47r   c                     y r   r   r  s     r   r  zShapeList.__getitem__  s    7:r   c                    t        |t              r#t        t        |       j	                  |            S t        |       j	                  |      S )z'Return slices of ShapeList as ShapeList)r   slicerz  r@  r  r  s     r   r  zShapeList.__getitem__  s;    c5!T$Z33C899Dz%%c**r   c                $    | j                  |      S )zSort operator >sort_byr   rY  s     r   __gt__zShapeList.__gt__  s    ||G$$r   c                *    | j                  |      d   S )z+Group and select smallest group operator <<r   group_byr   r^  s     r   
__lshift__zShapeList.__lshift__  s    }}X&q))r   c                (    | j                  |d      S )zReverse sort operator <Tr  rX  rZ  s     r   r  zShapeList.__lt__  s    ||GT|22r   c                \    t        |t              rt        |       t        |      k7  S t        S )z!ShapeLists inequality operator !=rR  r  s     r   __ne__zShapeList.__ne__  s*     (2%'CCIU#	
IW	
r   c                $    | j                  |      S )z%Filter by axis or geomtype operator |)r!  )r   r!  s     r   __or__zShapeList.__or__  s    ~~i((r   c                *    | j                  |      d   S )z*Group and select largest group operator >>r  r]  r_  s     r   
__rshift__zShapeList.__rshift__  s    }}X&r**r   c                B    t        t        |       t        |      z
        S )z-Differences between two ShapeLists operator -rO  r  s     r   r  zShapeList.__sub__  rP  r   c                H   t               }| D ]  }t        |t              r|j                  |       &t	        |d      s3t        |j
                  t              r2|j                  t        t        |            j                                t        |j
                  t              r |j                  |j                                t        |j
                  t              r |j                  |j                                |j                  r|j                  |        |S )zExpand by dissolving compounds, wires, and shells, filtering nulls.

        Returns:
            ShapeList with compounds dissolved to children, wires to edges,
            shells to faces, and nulls filtered out
        r   )rz  r   rs   r   rF  r   rT   rS  r@  rT  rY   r,  r\   r#  r   )r   expandedr   s      r   rT  zShapeList.expand  s     (k 	+E%(&	*emm_=OOId5k$:$A$A$CD|<OOEKKM2{;OOEKKM2OOE*	+ r   c                x    | st        ddd      S t        d | D        t        ddd            }|t        |       z  S )z9The average of the center of objects within the ShapeListr   c              3  <   K   | ]  }|j                           y wr   )r!  rZ  s     r   r8  z#ShapeList.center.<locals>.<genexpr>  s     51AHHJ5r  )rs   r^  r?  )r   total_centers     r   r!  zShapeList.center  s<    !Q?"55vaAGc$i''r   c                h    | j                         }t        |      }|dk7  rt        d|       |d   S )r  rx   z%Expected exactly one compound, found r   )r  r?  r   )r   r  compound_counts      r   r  zShapeList.compound  s=    NN$	YQD^DTUVV|r   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z/compounds - all the compounds in this ShapeList)rz  r  )r   r   cs      r   r  zShapeList.compounds  s.    Iu7HI!!I!IJJI   1
c                h    | j                         }t        |      }|dk7  rt        d|       |d   S )r  rx   z!Expected exactly one edge, found r   )r#  r?  r   )r   r#  
edge_counts      r   r   zShapeList.edge  9    

Z
?@MNNQxr   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z'edges - all the edges in this ShapeList)rz  r#  )r   r   r  s      r   r#  zShapeList.edges  -    Eu{{}E!!E!EFFErr  c                h    | j                         }t        |      }|dk7  rt        d|       |d   S )r(  rx   z!Expected exactly one face, found r   )r,  r?  r   )r   r,  
face_counts      r   r)  zShapeList.face  ru  r   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z'faces - all the faces in this ShapeList)rz  r,  )r   r   fs      r   r,  zShapeList.faces  rw  rr  Fc                P   dd}d	d}t              rnpt        t              rfdnZt        t              r ||      n?t        t              r ||      n$t        t
              rfdnt        d       |rfd}n}t        t        ||             S )
aP  filter by

        Either:
        - filter objects of type planar Face or linear Edge by their normal or tangent
        (respectively) and sort the results by the given axis, or
        - filter the objects by the provided type. Note that not all types apply to all
        objects.

        Args:
            filter_by (Callable[[T], bool] | Axis | Plane | GeomType): function, axis,
                plane, or geom type to filter and possibly sort by. Filtering by a plane
                returns faces/edges parallel to that plane.
            reverse (bool, optional): invert the geom type filter. Defaults to False.
            tolerance (float, optional): maximum deviation from axis. Defaults to 1e-5.

        Raises:
            ValueError: Invalid filter_by type

        Returns:
            ShapeList: filtered list of objects
        c                     d fd}|S )Nc                   t        | j                  t              rt        t	        j
                  | j                        t              j                         rt               }t               }t        j                  | j                        \  }}}}t        | j                        j                  ||||       t        |j                         |j!                         |j#                               j%                         }t'        | j)                         |      }nt        | j                  t*              r| j,                  t.        j0                  k(  rs| j3                         }|j5                         }	t               }
t               }|j7                  |	|
|       t        |
      }t        t9        |            }t'        ||      }nyj;                  |      S r   )r   r   rV   r>   r!   r   ri   r   rC   rE   r;   r  r7   r  rs   r  r  r  r  rj   r!  rU   r   rd   r  geom_adaptorFirstParameterD1rB   is_parallel)r   gp_pntr  u_valr  v_valr  
shape_axiscurveumintmpres	start_pos	start_dirr9  r  s                 r   predzBShapeList.filter_by.<locals>.axis_parallel_predicate.<locals>.pred<  sd   u}}k:/!++EMM:Ihj! $XF%+XN)2)=)=emm)L&E1eQ"5==188ufn 17&((*N,<,<,>@P@P@R1 jl . "&elln6O!PJu}}k:8==8!..0E //1D (C (CHHT3, &sI &vc{ 3I!%i!;J ''
I>>r   r   r   r   )r9  r  r  s   `` r   axis_parallel_predicatez4ShapeList.filter_by.<locals>.axis_parallel_predicate;  s    ?B Kr   c                `     t         j                   j                        d fdS )Nc           	     p   t        | j                  t              rt        t	        j
                  | j                        t              j                         rt               }t               }t        j                  | j                        \  }}}}t        | j                        j                  ||||       t        |      j                         }t!        | j#                         |      }j%                  |      S t        | j                  t&              r"t)        fd| j+                         D              S t        | j                  t,              r| j.                  yt1        t2        t1        t4        t7        | j.                        j9                         z        j:                  j                  j=                               }t1        t>        | j                  jA                               }	|	jC                         D ]9  }
|
jE                         stG        jH                  |
jK                         |      c S  yy)Nc              3  .   K   | ]  } |        y wr   r   )r7  r  r  s     r   r8  zVShapeList.filter_by.<locals>.plane_parallel_predicate.<locals>.pred.<locals>.<genexpr>t  s     >1tAw>s   F)&r   r   rV   r>   r!   r   ri   r   rC   rE   r;   r  r7   r  rs   r  rj   r!  r  r\   r  r#  rU   r   r   rF   rr   rn   inversern  XYZr    r  Curves	IsCurve3DrH   
IsPlanar_sCurve3D)r   r  r  r  r  r  r  r  	plane_xyzt_edger  plane
plane_axisr  r  s              r   r  zCShapeList.filter_by.<locals>.plane_parallel_predicate.<locals>.predb  s    u}}k:/!++EMM:Ihj! &,XF-3XN)2)=)=emm)L&E1eQ"5==188ufn 17~0F0Q0Q0S-!%elln6O!PJ%11*iHHemm[9>>>>emm[9~~-$ %!%%..)A)I)I)Ke)ST%	!I #:u}}/C/C/EFF!'  ??,#6#A#A %I$ 
 !r   r  )rj   rm  rn  )r  r  r  r  s   ``@@r   plane_parallel_predicatez5ShapeList.filter_by.<locals>.plane_parallel_predicate_  s)    ellEKK8J# #J Kr   c                &    j                  |       S r   )__get__r   r!  s    r   	predicatez&ShapeList.filter_by.<locals>.predicate  s     ((--r   )r  c                "    | j                   k(  S r   )r   r  s    r   r  z&ShapeList.filter_by.<locals>.predicate  s    }}	11r   z!Unsupported filter_by predicate: c                     |        S r   r   )r   r  s    r   actual_predicatez-ShapeList.filter_by.<locals>.actual_predicate  s    $U+++r   )r9  rj   r  r  )r  rr   r  r  )	callabler   r  rj   rr   rd   r   rz  rA  )r   r!  r   r  r  r  r  r  s    `     @r   r!  zShapeList.filter_by  s    :"	H(	V I!I	8,. 	4(/	YOI	5)0iPI	8,2 @LMM ,  ) 0$788r   c                    |dk(  rt        fd|       }n?|dk(  rt        fd|       }n(|dk(  rt        fd|       }nt        fd|       }t        |      j                        S )a  filter by position

        Filter and sort objects by the position of their centers along given axis.
        min and max values can be inclusive or exclusive depending on the inclusive tuple.

        Args:
            axis (Axis): axis to sort by
            minimum (float): minimum value
            maximum (float): maximum value
            inclusive (tuple[bool, bool], optional): include min,max values.
                Defaults to (True, True).

        Returns:
            ShapeList: filtered object list
        TTc                    t              j                  |       j                         j                  cxk  xr k  S c S r   rr   r  r!  r  r[  r9  maximumminimums    r   r   z.ShapeList.filter_by_position.<locals>.<lambda>  s<    ';..q188:<<   r   )TFc                    t              j                  |       j                         j                  cxk  xr k  S c S r   r  r  s    r   r   z.ShapeList.filter_by_position.<locals>.<lambda>  s<    ';..q188:<<   r   )FTc                    t              j                  |       j                         j                  cxk  xr k  S c S r   r  r  s    r   r   z.ShapeList.filter_by_position.<locals>.<lambda>  s<    '+--a0779;;   r   c                    t              j                  |       j                         j                  cxk  xr k  S c S r   r  r  s    r   r   z.ShapeList.filter_by_position.<locals>.<lambda>  s5    'E$K$?$?$B$I$I$K$M$MWPWW W r   )rA  rz  rY  )r   r9  r  r  	inclusiverb  s    ```  r   filter_by_positionzShapeList.filter_by_position  s    , $ 	G -' 	G -' 	G WG
 !))$//r      c                   t        t              rGj                  t        d      j                  J j                  j                         fd}nst        d      t        d      r't        j                  t        t        f      rfd}nt        t              r}t        j                  k(  rfd}nt        j                  k(  rfd}nt        j                  k(  rfd}nit        j                  k(  rfd	}nPt        j                  k(  r=fd
}n7t              rfd}n%t        t               rfd}nt        d       t#        | |      S )ai  group by

        Group objects by provided criteria and then sort the groups according to the criteria.
        Note that not all group_by criteria apply to all objects.

        Args:
            group_by (Callable[[T], K] | Axis | Edge | Wire | SortBy | property,
                optional): group and sort criteria. Defaults to Axis.Z.
            reverse (bool, optional): flip order of sort. Defaults to False.
            tol_digits (int, optional): Tolerance for building the group keys by
                round(key, tol_digits)

        Returns:
            GroupBy[T, K]: sorted groups of ShapeLists
        zCannot group by an empty axisc                x    t        t        | j                               z  j                  j                        S r   )roundrn   r!  r   r  )r   axis_as_location
tol_digitss    r   r  z!ShapeList.group_by.<locals>.key_f  s2    %(>>HHJJ r   zCannot group by an empty objectr   c                ~    j                  | j                               \  }}t        j                  |            S r   )r  r!  r  param_at_point)r   pnt1_pnt2r^  r  s      r   r  z!ShapeList.group_by.<locals>.key_f  s5    &55cjjlCeX44T:JGGr   c                0    t        | j                        S r   )r  r~  r   r  s    r   r  z!ShapeList.group_by.<locals>.key_f       Z88r   c                0    t        | j                        S r   )r  radiusr  s    r   r  z!ShapeList.group_by.<locals>.key_f  r  r   c                L    t        | j                         j                        S r   )r  r!  r~  r  s    r   r  z!ShapeList.group_by.<locals>.key_f  s     !4!4jAAr   c                0    t        | j                        S r   )r  r   r  s    r   r  z!ShapeList.group_by.<locals>.key_f  s     :66r   c                0    t        | j                        S r   )r  volumer  s    r   r  z!ShapeList.group_by.<locals>.key_f  r  r   c                P     |       }	 t        |      S # t        $ r |cY S w xY wr   )r  r  r   valr^  r  s     r   r  z!ShapeList.group_by.<locals>.key_f$  s2    sm j11  Js    %%c                b    j                  |       }	 t        |      S # t        $ r |cY S w xY wr   )r  r  r  r  s     r   r  z!ShapeList.group_by.<locals>.key_f-  s9    &&s+ j11  Js     ..zUnsupported group_by function: r  )r   rj   r   r   r   r  rF  rU   r\   rf   LENGTHRADIUSDISTANCEAREAVOLUMEr  r  r  )r   r^  r   r  r  r  s    ` ` @r   r^  zShapeList.group_by  s;   , h%' !@AA$$000'0088: >??Xy)j{K8/
H &)6==(9 V]]*9 V__,B V[[(7 V]]*9 h (+ >xjIJJ udG44r   c                h    | j                         }t        |      }|dk7  rt        d|       |d   S )r  rx   z"Expected exactly one shell, found r   )r  r?  r   )r   r  shell_counts      r   r  zShapeList.shell:  ;    &k!A+OPPayr   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z)shells - all the shells in this ShapeList)rz  r  r   r   r  s      r   r  zShapeList.shellsB  -    Fu||~F!!F!FGGFrr  c                h    | j                         }t        |      }|dk7  rt        d|       |d   S )r  rx   z"Expected exactly one solid, found r   )r  r?  r   )r   r  solid_counts      r   r  zShapeList.solidF  r  r   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z)solids - all the solids in this ShapeList)rz  r  r  s      r   r  zShapeList.solidsN  r  rr  c                  	 t              rt        | |      }t'        |      S t        t              r#t        | j                  |      }t'        |      S t        t
              r[j                  t        d      j                  J j                  j                         t        | fd|      }t'        |      S st        d      t        d      rBt        j                  t        t        f      r"dfd	t        | 	fd|      }t'        |      S t        t              r5t        j                  k(  rt        | d |      }t'        |      S t        j                  k(  r6| D cg c]  }t        |d	      s| }}t        |d
 |      }t'        |      S t        j                   k(  rt        | d |      }t'        |      S t        j"                  k(  r6| D cg c]  }t        |d      s| }}t        |d |      }t'        |      S t        j$                  k(  rA| D cg c]  }t        |d      s| }}t        |d |      }t'        |      S t        d      t'              S c c}w c c}w c c}w )a^  sort by

        Sort objects by provided criteria. Note that not all sort_by criteria apply to all
        objects.

        Args:
            sort_by (Callable[[T], K] | Axis | Edge | Wire | SortBy | property,
                optional): sort criteria. Defaults to Axis.Z.
            reverse (bool, optional): flip order of sort. Defaults to False.

        Raises:
            ValueError: Cannot sort by an empty axis
            ValueError: Cannot sort by an empty object
            ValueError: Invalid sort_by criteria provided

        Returns:
            ShapeList: sorted list of objects
        r  zCannot sort by an empty axisc                    t        t        t        | j                               z        j                  j                  S r   )r   rn   r!  r   r  )r[  r  s    r   r   z#ShapeList.sort_by.<locals>.<lambda>x  s.    e/(188:2FF(11 r   zCannot sort by an empty objectr   c                    t        t              rJ j                  | j                               \  }}j	                  |      S )z:u-value of closest point between object center and sort_by)r   rf   r  r!  r  )r   r  r  rY  s      r   u_of_closest_centerz.ShapeList.sort_by.<locals>.u_of_closest_center  s>    %gv666%44SZZ\Be--d33r   c                     |       S r   r   )r[  r  s    r   r   z#ShapeList.sort_by.<locals>.<lambda>  s    $7$: r   c                    | j                   S r   r  r   s    r   r   z#ShapeList.sort_by.<locals>.<lambda>  
    CJJ r   r  c                    | j                   S r   )r  r  s    r   r   z#ShapeList.sort_by.<locals>.<lambda>  r  r   c                6    | j                         j                  S r   )r!  r~  r  s    r   r   z#ShapeList.sort_by.<locals>.<lambda>  s    CJJL$7$7 r   r   c                    | j                   S r   )r   r  s    r   r   z#ShapeList.sort_by.<locals>.<lambda>  s
    CHH r   r  c                    | j                   S r   )r  r  s    r   r   z#ShapeList.sort_by.<locals>.<lambda>  r  r   z!Invalid sort_by criteria providedr{  )r  rY  r   r  r  rj   r   r   r   r  rF  rU   r\   rf   r  r  r  r  r  rz  )
r   rY  r   rb  r   with_radius	with_areawith_volumer  r  s
    `      @@r   rY  zShapeList.sort_byR  s   0 GTw@GN !!K *TwHGH !!E && !?@@##///&//779  Gz !!m =>>Wi(ZOOk;7.
4 :GGR !!K (&--' .#F !!= FMM).2Msgc86LsMM .#8 !!/ FOO+ 7#, !!# FKK',0ISGC4HSI	I ,# !! FMM).2Msgc86LsMM .# !! @AA!!; N J Ns$   6I=I=,J>J5JJc                    t        | D cg c]  }|j                  |      |f c}d |      }t        |D cg c]  }|d   	 c}      S c c}w c c}w )a&  Sort by distance

        Sort by minimal distance between objects and other

        Args:
            other (Union[Shape,VectorLike]): reference object
            reverse (bool, optional): flip order of sort. Defaults to False.

        Returns:
            ShapeList: Sorted shapes
        c                    | d   S r2  r   r  s    r   r   z,ShapeList.sort_by_distance.<locals>.<lambda>  s
    CF r   r  rx   )rY  r	  rz  )r   r  r   r   r  s        r   sort_by_distancezShapeList.sort_by_distance  sV     6:;scooe$c*;"
	
 I6S#a&677	 < 7s
   AAc                h    | j                         }t        |      }|dk7  rt        d|       |d   S )rv  rx   z#Expected exactly one vertex, found r   )r,  r?  r   )r   r,  vertex_counts      r   rw  zShapeList.vertex  s;    ==?8}1B<.QRR{r   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z-vertices - all the vertices in this ShapeList)rz  r,  )r   r   r/  s      r   r,  zShapeList.vertices  s.    Hu~~7GH!!H!HIIHrr  c                h    | j                         }t        |      }|dk7  rt        d|       |d   S )rM  rx   z!Expected exactly one wire, found r   )rP  r?  r   )r   rP  
wire_counts      r   rN  zShapeList.wire  ru  r   c                n    t        | D cg c]  }|j                         D ]  }|  c}}      S c c}}w )z'wires - all the wires in this ShapeList)rz  rP  )r   r   ws      r   rP  zShapeList.wires  rw  rr  N)r  r  )r  r  r  ShapeList[T])r  r  r  ra   )r  rz  r  r  )r  objectr  r}  )r  r   r  r  )r  rV  r  r  )r  zSupportsIndex | slicer  zT | ShapeList[T])rY  Axis | SortByr  r  )r^  r  r  r  )r  rz  r  r}  )r!  zAxis | GeomTyper  r  )r  rz  r  r  r  r  r  r  r  )Fgh㈵>)r!  z8Callable[[T], bool] | Axis | Plane | GeomType | propertyr   r}  r  r  r  r  )r  )
r9  rj   r  r  r  r  r  ztuple[bool, bool]r  r  )r^  9Callable[[T], K] | Axis | Edge | Wire | SortBy | propertyr   r}  r  r  r  zGroupBy[T, K]r  r  r  r  )rY  r  r   r}  r  r  r  )r  r  r   r}  r  r  r  r  r  r  )+r   r   r   r   r  r  rE  r  rM  r  r  r   r  rj   r  r[  r`  r  rc  re  rg  r  rT  r!  r  r  r   r#  r)  r,  r!  r  r^  r  r  r  r  rY  r  rw  r,  rN  rP  r   r   r   rz  rz  z  s   Q    Q
1
 7 7: :+ /3ff % 4866 * /3ff 3
 37&& ) 4866 +1.(KGG 	H9KH9 H9 	H9
 
H9^ (41010 10 	10
 %10 
10j OSff	]5K]5 ]5 	]5
 
]5~HH NRVVa"Ja" a" 
	a"H :?8'8268	8*JGr   rz  c                  z    e Zd ZdZd	dZeed
d              Zeedd              Zed        Z	ed
d       Z
ddZy)JointaP  Joint

    Abstract Base Joint class - used to join two components together

    Args:
        parent (Union[Solid, Compound]): object that joint to bound to

    Attributes:
        label (str): user assigned label
        parent (Shape): object joint is bound to
        connected_to (Joint): joint that is connect to this joint

    c                .    || _         || _        d | _        y r   )r   r   connected_to)r   r   r   s      r   r   zJoint.__init__  s    
*.r   c                     y)zLocation of jointNr   r   s    r   r   zJoint.location  r   r   c                     y)z?A CAD object positioned in global space to illustrate the jointNr   r   s    r   symbolzJoint.symbol   r   r   c                     y)z4All derived classes must provide a connect_to methodNr   r   r]  kwargss      r   
connect_tozJoint.connect_to  r   r   c                     y)z)Return relative location to another jointNr   r  s      r   relative_tozJoint.relative_to  r   r   c                H   t        |t              st        dt        |             | j                  j
                  t        d       | j                  |fi |}|j                  j                  t        t        | j                  j
                  |z               || _        y)z)Connect Joint self by repositioning otherzother must of type Joint not NzParent location is not set)r   r  r  r  r   r   r   r   rb  r   rn   r  )r   r  r  relative_locations       r   _connect_tozJoint._connect_to  s     %';DK=IJJ;;'9::,D,,U=f=E(DKK,@,@CT,TUV!r   N)r   r   r   zBuildPart | Solid | Compoundr~  r  )r  r  )r   r   r   r   r   r  r   r   r  r  r   r  r   r   r   r  r    su     /      N  N
 C C 8 8	"r   r  c                       e Zd ZdZdZd Zd Zy)r  zRSkip clean context for use in operator driven code where clean=False wouldn't workTc                    dt         _        y r   r  r  r   s    r   	__enter__zSkipClean.__enter__!  s	    	r   c                    dt         _        y r  r  )r   exception_typeexception_value	tracebacks       r   __exit__zSkipClean.__exit__$  s	    	r   N)r   r   r   r   r  r  r  r   r   r   r  r    s    \E r   r  c                    t               }| D ]  }|j                  |        |j                          t        |j	                               S )z"Sew faces into a shell if possible)r0   r  r  r   
SewedShape)r,  shell_builderr)  s      r   r  r  (  sG    )+M  $ M,,.//r   c                   t        |       } t        |      }t               }| D ]  }|j                  |        t               }|D ]  }|j                  |        |j                  |       |j	                  |       |j                  d       |j                          t        |j                               }t        |t              rt        |d      }|S )zGeneric boolean operation for TopoDS_Shapes

    Args:
        args: Iterable[TopoDS_Shape]:
        tools: Iterable[TopoDS_Shape]:
        operation: BRepAlgoAPI_BooleanOperation | BRepAlgoAPI_Splitter:

    Returns: TopoDS_Shape

    T)r@  r^   r  r  r  r\  r  r   r   r   rT   r  )r]  r^  r_  rb  r   r  rQ  s          r   r  r  1  s     :DKE

 C 

3  !D C 3tT"OOioo'(F&/*'5Mr   c                   i }t        | t        j                  |         }|j                         r?|j	                         }||t        |      <   |j                          |j                         r?t        |j                               S )z<Return the TopoDS_Shapes of topo_type from this TopoDS_Shape)	rP   r   r  r$  r  r  r(  r@  r  )r   r&  outrn  r}  s        r   r%  r%  X  si    
Cue&=&=i&HIH
--/!DJ --/
 

r   c                    t        j                  |       }t        ||      }|j                         \  }}t	               }t               }t        |       j                  ||||       t        |      j                         S )z%Find the normal at a point on surface)
r!   r   r=   LowerDistanceParametersrC   rE   r7   r  rs   r  )r)  r  r   	projectorr  r  r  normals           r   _topods_face_normal_atr  f  sl    !!$'G +='BI446LE5XFXF4uff=&>$$&&r   c                N    t         j                  t        |          } ||       }|S )znDowncasts a TopoDS object to suitable specialized type

    Args:
      obj: TopoDS_Shape:

    Returns:

    )r   r  r   )r   
f_downcastrJ  s      r   r   r   u  s'     ((38Jc?Lr   c                j    t        |       }|j                          t        |j                               S )zhFix a TopoDS object to suitable specialized type

    Args:
      obj: TopoDS_Shape:

    Returns:

    )rK   r  r   r   )r   	shape_fixs     r   rA  rA    s,     s#IIOO%&&r   c                   | 
t               S g }| g}|r|j                         }t        |t              rt	               }|j                  |       |j                         rt        |j                               }t        |t              r|j                  |       n|j                  |       |j                          |j                         rmn|j                  |       |r|S )a   
    Retrieve the first level of child shapes from the shape.

    This method collects all the non-compound shapes directly contained in the
    current shape. If the wrapped shape is a `TopoDS_Compound`, it traverses
    its immediate children and collects all shapes that are not further nested
    compounds. Nested compounds are traversed to gather their non-compound elements
    without returning the nested compound itself.

    Returns:
        list[TopoDS_Shape]: A list of all first-level non-compound child shapes.

    Example:
        If the current shape is a compound containing both simple shapes
        (e.g., edges, vertices) and other compounds, the method returns a list
        of only the simple shapes directly contained at the top level.
    )rz  r   r   rT   rW   r#  r$  r   r   r   r(  )r  first_level_shapesstackcurrent_shaper-  child_shapes         r   r   r     s    ( {NE
		m_5&(H.--/&x~~'78k?;LL- '--k: --/ %%m4 " r   c                \    | | j                         rt        d      | j                         S )z&Return TopoDS_Shape's TopAbs_ShapeEnumzNull TopoDS_Shape object)r   r   r  r  s    r   r   r     s'    
{cjjl344==?r   c                P   t         fdt        t        fdt        t        fdt
        fdi}|j                         D ]  \  }}t        | |      s|c S  t        | t              rAt        |       D ch c]  }t        |       }}t        |      dk(  r|j                         S dS yc c}w )z)Return the dimension of this TopoDS_Shaper   rx   r   r   N)r[   rU   r\   rV   rY   rZ   r  r   rT   r   
topods_dimr?  r   )topodsshape_dim_mapshape_typesdimr  sub_dimss         r   r#  r#    s     
!	k"A	l#Q		M *//1 Sfk*J &/*+Fv+NOaJqMOO!$X!!3x||~== Ps   .B#c                    | j                         dk(  rFt        |       }t        |j                               }t	        |t
              rt        ||      S |r|S | S | S )aU  Strip unnecessary Compound wrappers

    Args:
        compound (TopoDS_Compound): The TopoDS_Compound to unwrap.
        fully (bool, optional): return base shape without any TopoDS_Compound
            wrappers (otherwise one TopoDS_Compound is left). Defaults to True.

    Returns:
        TopoDS_Compound | TopoDS_Shape: base shape
    rx   )
NbChildrenrW   r   r   r   rT   r  )r  fullyr-  single_elements       r   r  r    s]     !"8,!(.."23 no6).%@@!&~4H4 Or   c                    t               }t               }|j                  |       | D ]  }||j                  ||        |S )zCreate an OCCT TopoDS_Compound

    Create an OCCT TopoDS_Compound object from an iterable of TopoDS_Shape objects

    Args:
        occt_shapes (Iterable[TopoDS_Shape]): OCCT shapes

    Returns:
        TopoDS_Compound: OCCT compound
    )rT   rS   MakeCompoundr  )occt_shapescompcomp_builderr   s       r   r[  r[    sN     D!#Ld# *T5)* Kr   )r  r  r  zCallable[[Shape], int | float])r,  zIterable[TopoDS_Face]r  rX   )r]  Iterable[TopoDS_Shape]r^  r2  r_  r  r  rX   )r   rX   r&  r  r  r  )r)  rV   r  rC   r  rs   )r   rX   r  rX   )r  ry  r  r  )r   ry  r  rN   )r$  rX   r  r   )T)r  rT   r+  r}  r  zTopoDS_Compound | TopoDS_Shape)r/  zIterable[TopoDS_Shape | None]r  rT   )r   
__future__r   r  r  r  abcr   r   collectionsr   collections.abcr   r   r	   	functoolsr
   mathr   typingr   r   r   r   r   r   r   r   r   r   r   r   r   OCP.GeomAbsGeomAbsr4  
OCP.TopAbsTopAbsr   anytreer   r   IPython.lib.prettyr   r   OCP.Bndr   r   OCP.BOPAlgor   OCP.BRepr    r!   OCP.BRepAdaptorr"   r#   OCP.BRepAlgoAPIr$   r%   r&   r'   r(   r)   OCP.BRepBuilderAPIr*   r+   r,   r-   r.   r/   r0   r1   r2   OCP.BRepCheckr3   OCP.BRepExtremar4   OCP.BRepFeatr5   OCP.BRepGPropr6   r7   OCP.BRepIntCurveSurfacer8   OCP.BRepMeshr9   OCP.BRepPrimAPIr:   OCP.BRepToolsr;   OCP.gcer<   OCP.GeomAPIr=   OCP.GeomLibr>   OCP.gpr?   r@   rA   rB   rC   rD   rE   rF   	OCP.GProprG   OCP.ShapeAnalysisrH   OCP.ShapeCustomrI   rJ   OCP.ShapeFixrK   OCP.ShapeUpgraderL   rM   rN   
OCP.TopExprO   rP   
OCP.TopLocrQ   
OCP.TopoDSrR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r\   OCP.TopToolsr]   r^   r_   r`   typing_extensionsra   rb   build123d.build_enumsrc   rd   re   rf   rg   build123d.geometryrh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   build123d.build_partrw   	compositery   one_drz   r{   three_dr|   two_dr}   r~   zero_dr   r  r  r   CalcFnr  r   r  r  r  r  r  rA  r@  rz  r  r  r  r  r%  r  r   rA  r   r   r#  r  r[  r   r   r   <module>re     s  ,\ #    #  8 8     !    ) < $ ( * B 
 
 
 - 6 , 3 = 1 5 #  2 / R R R " 1 J ' 9 ; . &     / N N    $ .#!"	O	PUGV+,		.	<.4	5Xg./89 }&4Iwv }&4@N	. 	..x . CuUF]+,C'(G)gadm G)Tf"f#fRf	GQ f	GR5"C 5"p
 
0$
 $!$ C$ 	$N' ' +%++\* .2&*#6.r   