Ë
    JÿiGß  ã                  ó
  — d Z ddlmZ ddlZddlZddlmZmZmZ ddl	m
Z
mZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ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$ ddl%m&Z&m'Z' ddl(m)Z)m*Z* ddl+m,Z, ddl-m.Z.m/Z/m0Z0 ddl1m2Z2m3Z3 ddl4m5Z5 ddl6m7Z7 ddl8m9Z9 ddl:m;Z;m<Z<m=Z= ddl>m?Z? ddl@mAZA ddlBmCZC ddlDmEZE ddlFmGZG ddlHmIZImJZJmKZKmLZLmMZM ddlNmOZO dd lPmQZQmRZR dd!lSmTZTmUZUmVZVmWZWmXZX dd"lYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZa dd#lbmcZc d$d%ldmeZemfZfmgZg d$d&lhmiZimjZjmkZkmlZlmmZmmnZnmoZompZpmqZq d$d'lrmsZsmtZtmuZumvZvmwZw d$d(lxmyZy erd$d)lzm{Z{ d$d*l|m}Z}m~Z~mZm€Z€  G d+„ d,ei«      Z� G d-„ d.e�eieJ   «      Z‚ G d/„ d0e�eieL   «      Zƒd2d1„Z„y)3u™  
build123d topology

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

desc:

This module provides classes and methods for two-dimensional geometric entities in the build123d CAD
library, focusing on the `Face` and `Shell` classes. These entities form the building blocks for
creating and manipulating complex 2D surfaces and 3D shells, enabling precise modeling for CAD
applications.

Key Features:
- **Mixin2D**:
  - Adds shared functionality to `Face` and `Shell` classes, such as splitting, extrusion, and
    projection operations.

- **Face Class**:
  - Represents a 3D bounded surface with advanced features like trimming, offsetting, and Boolean
    operations.
  - Provides utilities for creating faces from wires, arrays of points, BÃ©zier surfaces, and ruled
    surfaces.
  - Enables geometry queries like normal vectors, surface centers, and planarity checks.

- **Shell Class**:
  - Represents a collection of connected faces forming a closed surface.
  - Supports operations like lofting and sweeping profiles along paths.

- **Utilities**:
  - Includes methods for sorting wires into buildable faces and creating holes within faces
    efficiently.

The module integrates deeply with OpenCascade to leverage its powerful CAD kernel, offering robust
and extensible tools for surface and shell creation, manipulation, and analysis.

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)ÚAnyÚoverloadÚTYPE_CHECKING)ÚIterableÚSequence)Ú	BRep_Tool)ÚBRepAdaptor_Surface)ÚBRepAlgo)ÚBRepAlgoAPI_Common)ÚBRepBuilderAPI_MakeFaceÚBRepBuilderAPI_MakeShell)ÚBRepClass3d_SolidClassifier)ÚBRepFill)ÚBRepFilletAPI_MakeFillet2d)Ú	BRepGPropÚBRepGProp_Face)ÚBRepIntCurveSurface_Inter)ÚBRepOffsetAPI_MakeFillingÚBRepOffsetAPI_MakePipeShell)Ú	BRepToolsÚBRepTools_ReShape)ÚGProp_GProps)ÚGeom_BezierSurfaceÚGeom_SurfaceÚGeom_RectangularTrimmedSurface)ÚGeomAPI_PointsToBSplineSurfaceÚGeomAPI_ProjectPointOnSurf)Ú
GeomAbs_C0)Ú	Precision)ÚShapeFix_Solid)ÚStandard_FailureÚStandard_NoSuchObjectÚStandard_ConstructionError)ÚStdFail_NotDone)ÚTColStd_HArray2OfReal)ÚTColgp_HArray2OfPnt)ÚTopExp)Ú)TopTools_IndexedDataMapOfShapeListOfShape)ÚTopoDSÚTopoDS_FaceÚTopoDS_ShapeÚTopoDS_ShellÚTopoDS_Solid)Úgce_MakeLin)Úgp_PntÚgp_Vec)ÚCenterOfÚGeomTypeÚKeepÚSortByÚ
Transition)Ú	TOLERANCEÚAxisÚColorÚLocationÚOrientedBoundBoxÚPlaneÚVectorÚ
VectorLike)ÚSelfé   )ÚMixin1DÚEdgeÚWire)	ÚShapeÚ	ShapeListÚ	SkipCleanÚdowncastÚget_top_level_topods_shapesÚ_sew_topods_facesÚ	shapetypeÚ_topods_entitiesÚ_topods_face_normal_at)Ú_extrude_topods_shapeÚfind_max_dimensionÚ
_make_loftÚ_make_topods_face_from_wiresÚ_topods_bool_op)ÚVertex)ÚSolid)ÚCompoundÚCurveÚSketchÚPartc                  ó@  — e Zd ZdZej
                  Zej                  Zej                  Zej                  Zej                  Z	ej                  Z
ej                  Zedd„«       Zedd„«       Ze	 	 	 	 	 	 dd„«       Zdd„Zdd„Zdd„Zef	 	 	 	 	 dd„Zdd	„Zdd
„Zdd„Zy)ÚMixin2Dz1Additional methods to add to Face and Shell classc                 ó   — y)zDimension of Faces and Shellsé   © ©Úselfs    úi/workspace/moltex-experiments/.pixi/envs/default/lib/python3.12/site-packages/build123d/topology/two_d.pyÚ_dimzMixin2D._dim–   s   € ð ó    c           
     ó  — t         j                  t        t         j                  t        t         j
                  t        t         j                  t        t         j                  t        i}t        |«      } ||   t        |«      «      S )z6Returns the right type of wrapper, given a OCCT object)ÚtaÚTopAbs_VERTEXrR   ÚTopAbs_EDGErB   ÚTopAbs_WIRErC   ÚTopAbs_FACEÚFaceÚTopAbs_SHELLÚShellrJ   rG   )ÚclsÚobjÚconstructor_lutÚ
shape_types       r_   ÚcastzMixin2D.cast�   s[   € ô ×ÑœfÜ�N‰NœDÜ�N‰NœDÜ�N‰NœDÜ�O‰OœUð
ˆô ˜s“^ˆ
à*ˆ˜zÑ*¬8°C«=Ó9Ð9ra   c                ó   — t         S )z9Unused - only here because Mixin1D is a subclass of Shape)ÚNotImplemented©rk   rl   Ú	directions      r_   ÚextrudezMixin2D.extrude®   s
   € ô
 Ðra   c                ó®   — | j                   €t        d«      ‚t        j                  | «      }t	        | j                   j                  «       «      |_         |S )zReverse normal operator -zInvalid Shape)ÚwrappedÚ
ValueErrorÚcopyÚdeepcopyrG   ÚComplemented)r^   Únew_surfaces     r_   Ú__neg__zMixin2D.__neg__·   sE   € à�<‰<ÐÜ˜_Ó-Ð-Ü—m‘m DÓ)ˆÜ& t§|¡|×'@Ñ'@Ó'BÓCˆÔàÐra   c                ó.   — t        j                  | d«      S )zReturn the Facerh   ©rD   Úget_single_shaper]   s    r_   ÚfacezMixin2D.faceÀ   s   € ä×%Ñ% d¨FÓ3Ð3ra   c                ó.   — t        j                  | d«      S )z#faces - all the faces in this Shaperh   ©rD   Úget_shape_listr]   s    r_   ÚfaceszMixin2D.facesÄ   s   € ä×#Ñ# D¨&Ó1Ð1ra   c           	     óF  — | j                   €g S t        |j                   «      j                  «       }t        «       }|j	                  | j                   ||«       g }|j                  «       rŽ|j                  «       }|j                  «       j                  t        |«      «      j                  }|j                  |j                  «       t        |«      |f«       |j                  «        |j                  «       rŒŽ|j                  d„ ¬«       |D �cg c]  }|d   ‘Œ	 }	}|D �cg c]  }|d   ‘Œ	 }
}t        |	«      D ��cg c]"  \  }}t!        ||
|   j#                  «       «      ‘Œ$ }}}g }t%        |
|«      D ]  \  }}|j                  ||f«       Œ |S c c}w c c}w c c}}w )a4  Find point and normal at intersection

        Return both the point(s) and normal(s) of the intersection of the axis and the shape

        Args:
            axis (Axis): axis defining the intersection line

        Returns:
            list[tuple[Vector, Vector]]: Point and normal of intersection
        c                ó   — | d   S )Nr[   r\   )Úxs    r_   Ú<lambda>z2Mixin2D.find_intersection_points.<locals>.<lambda>ê   s   € ¨¨1ªra   )Úkeyr   r@   )rv   r/   ÚValuer   ÚInitÚMoreÚPntÚto_planeÚto_local_coordsr=   ÚZÚappendrh   ÚNextÚsortÚ	enumeraterL   Úto_pntÚzip)r^   ÚotherÚ	toleranceÚintersection_lineÚintersect_makerÚintersectionsÚinter_ptÚdistanceÚiÚintersecting_facesÚintersecting_pointsÚfÚintersecting_normalsÚresultÚpntÚnormals                   r_   Úfind_intersection_pointsz Mixin2D.find_intersection_pointsÈ   s›  € ð �<‰<ÐØˆIä'¨¯©Ó6×<Ñ<Ó>ÐÜ3Ó5ˆØ×Ñ˜TŸ\™\Ð+<¸iÔHàˆØ×"Ñ"Ô$Ø&×*Ñ*Ó,ˆHà—~‘~Ó'×7Ñ7¼¸xÓ8HÓI×KÑKˆHØ× Ñ à#×(Ñ(Ó*Ü˜8Ó$Øðôð × Ñ Ô"ð ×"Ñ"Õ$ð 	×Ñ™~ÐÔ.Ù,9Ó:©M q˜a ›d¨MÐÐ:Ù-:Ó;©]¨˜q ›t¨]ÐÐ;ô "Ð"4Ô5ô 
á5‘��1ô # 1Ð&9¸!Ñ&<×&CÑ&CÓ&EÕFØ5ð 	ñ  
ð ˆÜÐ2Ð4HÖI‰KˆC�Ø�M‰M˜3 ˜-Õ(ð Jð ˆùò ;ùÚ;ùó 
s   ÄFÄ"FÄ>'Fc                ó~   — t        j                  | «      j                  t        | j	                  «       |z  «      «      S )z6Return a copy of self moved along the normal by amount)rx   ry   Úmovedr:   Ú	normal_at)r^   Úamounts     r_   ÚoffsetzMixin2D.offset÷   s-   € ä�}‰}˜TÓ"×(Ñ(¬°$·.±.Ó2BÀVÑ2KÓ)LÓMÐMra   c                ó.   — t        j                  | d«      S )zReturn the Shellrj   r~   r]   s    r_   ÚshellzMixin2D.shellû   s   € ä×%Ñ% d¨GÓ4Ð4ra   c                ó.   — t        j                  | d«      S )z%shells - all the shells in this Shaperj   r‚   r]   s    r_   ÚshellszMixin2D.shellsÿ   s   € ä×#Ñ# D¨'Ó2Ð2ra   N)ÚreturnÚint)rl   r,   r°   z#Vertex | Edge | Wire | Face | Shell)rl   rD   rs   r>   r°   z&Edge | Face | Shell | Solid | Compound)r°   r?   )r°   zFace | None)r°   zShapeList[Face])r—   r8   r˜   Úfloatr°   zlist[tuple[Vector, Vector]])rª   r²   r°   r?   )r°   zShell | None)r°   zShapeList[Shell])Ú__name__Ú
__module__Ú__qualname__Ú__doc__rA   Úproject_to_viewportÚsplitÚverticesÚvertexÚedgesÚedgeÚwiresÚpropertyr`   Úclassmethodro   rt   r|   r€   r„   r7   r¦   r«   r­   r¯   r\   ra   r_   rY   rY   ‰   sß   „ Ù;à!×5Ñ5ÐØ�M‰M€Eà×Ñ€HØ�^‰^€FØ�M‰M€EØ�<‰<€DØ�M‰M€Eð òó ðð ò:ó ð:ð  ðØðØ$.ðà	/òó ðóó4ó2ð
 /8ð-Øð-Ø&+ð-à	$ó-ó^Nó5ô3ra   rY   c                  ó¼  ‡ — e Zd ZdZdZe	 	 	 d.	 	 	 	 	 	 	 d/d„«       Ze	 	 	 	 d0	 	 	 	 	 	 	 	 	 d1d„«       Zd2ˆ fd„Zed3d„«       Zed4d„«       Z	ed5d„«       Z
ed6d	„«       Zed7d
„«       Zed8d„«       Zed8d„«       Zed9d„«       Zed3d„«       Zed8d„«       Zed:d„«       Ze	 d;	 	 	 	 	 d<d„«       Zeej,                  f	 	 	 d=d„«       Zeej,                  fd>d„«       Ze	 	 d?	 	 	 	 	 	 	 d@d„«       Ze	 	 	 	 dA	 	 	 	 	 	 	 	 	 	 	 dBd„«       Zee	 	 	 	 	 	 dCd„«       «       Zee	 	 	 	 	 	 dDd„«       «       ZedEd„«       ZedFd„«       Zeej<                  f	 	 	 	 	 dGd„«       Ze jB                  fdHd„Z"	 d;	 	 	 	 	 	 	 	 	 dId„Z#dJd„Z$dKd„Z%dLd„Z&dMd „Z'dNdOd!„Z(	 d;	 	 	 	 	 	 	 dPd"„Z)dQd#„Z*ed;dRd$„«       Z+edSd%„«       Z+dTd&„Z+dUd'„Z,dSd(„Z-	 	 	 	 	 	 dVd)„Z.dWdXd*„Z/dEd+„Z0dUd,„Z1dYd-„Z2ˆ xZ3S )Zrh   aŠ  A Face in build123d represents a 3D bounded surface within the topological data
    structure. It encapsulates geometric information, defining a face of a 3D shape.
    These faces are integral components of complex structures, such as solids and
    shells. Face enables precise modeling and manipulation of surfaces, supporting
    operations like trimming, filleting, and Boolean operations.g       @c                 ó   — y)a5  Build a Face from an OCCT TopoDS_Shape/TopoDS_Face

        Args:
            obj (TopoDS_Shape, optional): OCCT Face.
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr\   )r^   rl   ÚlabelÚcolorÚparents        r_   Ú__init__zFace.__init__  ó   � ra   c                 ó   — y)a’  Build a planar Face from a boundary Wire with optional hole Wires.

        Args:
            outer_wire (Wire): closed perimeter wire
            inner_wires (Iterable[Wire], optional): holes. Defaults to None.
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr\   )r^   Ú
outer_wireÚinner_wiresrÂ   rÃ   rÄ   s         r_   rÅ   zFace.__init__!  rÆ   ra   c                óê  •— d\  }}}}}}|rYt        |«      }	t        |d   t        «      r|d d dd|	z
  z  z   \  }}}}n't        |d   t        «      r|d d dd|	z
  z  z   \  }}}}}dj	                  t        |j                  «       «      j                  g d¢«      «      }
|
rt        d|
› �«      ‚|j                  d	|«      }|j                  d
|«      }|j                  d|«      }|j                  d|«      }|j                  d|«      }|j                  d|«      }|�4|�|D �cg c]  }|j                  ‘Œ c}ng }t        |j                  |«      }t        ‰| �5  ||€dn|||¬«       d | _        y c c}w )N)NNNNNNr   é   ©Né   ú, )rÈ   rÉ   rl   rÂ   rÃ   rÄ   úUnexpected argument(s) rl   rÈ   rÉ   rÂ   rÃ   rÄ   Ú ©rl   rÂ   rÃ   rÄ   )ÚlenÚ
isinstancer,   rC   ÚjoinÚsetÚkeysÚ
differencerw   Úgetrv   rP   ÚsuperrÅ   Ú
created_on)r^   ÚargsÚkwargsrÈ   rÉ   rl   rÂ   rÃ   rÄ   Úl_aÚunknown_argsÚwÚinner_topods_wiresÚ	__class__s                €r_   rÅ   zFace.__init__4  s   ø€ Ø=HÑ:ˆ
�K  e¨U°FáÜ�d“)ˆCÜ˜$˜q™'¤<Ô0Ø,0°°!¨H°wÀ!ÀcÁ'Ñ7JÑ,JÑ)��U˜E¡6Ü˜D ™G¤TÔ*Ø@DÀRÀaÀÈ7Ø˜‘GñLñ AÑ=�
˜K¨°°vð —y‘yÜ�—‘“Ó×)Ñ)òó	ó
ˆñ ÜÐ6°|°nÐEÓFÐFà�j‰j˜ Ó$ˆØ—Z‘Z ¨jÓ9ˆ
Ø—j‘j °Ó<ˆØ—
‘
˜7 EÓ*ˆØ—
‘
˜7 EÓ*ˆØ—‘˜H fÓ-ˆàÐ!à4?Ð4K¡KÓ0¡K˜q�—“ KÒ0ÐQSð ô /¨z×/AÑ/AÐCUÓVˆCä‰ÑØØ˜‘"¨5ØØð	 	ô 	
ð )-ˆ�ùò 1s   Ä#E0c                óP   — | j                   €y| j                  «       j                  S )a`  
        Calculate the total surface area of the face, including the areas of any holes.

        This property returns the overall area of the face as if the inner boundaries (holes)
        were filled in.

        Returns:
            float: The total surface area, including the area of holes. Returns 0.0 if
            the face is empty.
        ç        )rv   Úwithout_holesÚarear]   s    r_   Úarea_without_holeszFace.area_without_holesg  s&   € ð �<‰<ÐØà×!Ñ!Ó#×(Ñ(Ð(ra   c                ó(  ‡!‡"— | j                   €t        d«      ‚| j                  st        d«      ‚| j                  «       }| j	                  «       }| j                  «       }|rˆ|D �cg c]  }t        |«      ‘Œ }}t        j                  |«      }t        ||z
  «      t        kD  r||z
  j                  «       g}�n@|D �cg c]#  }|j                  «       |z
  j                  «       ‘Œ% }}�n| j                  «       j                  «       j                  t        j                  d¬«      }	| j                  «       j                  «       }
|	rxt!        | «      }|j"                  }t%        t'        d«      D �cg c]$  }t)        j*                  ||   ||dz   dz     «      ‘Œ& c}«      }|
|z   D ��cg c]  }dD ]  }||z  ‘Œ	 Œ }}}n|
D ��cg c]  }dD ]  }||z  ‘Œ	 Œ }}}|D �cg c]  }||z
  j                  «       ‘Œ }}t-        «       }|D �]É  Š!t/        |‰!‰!j1                  |«      ¬«      Š"| j3                  ‰"t4        j6                  ¬	«      \  }}t9        |«      t9        |«      k7  rŒ]|�|€Œbt%        t;        |t<        «      r|n|g«      }t%        t;        |t<        «      r|n|g«      }t?        |«      t?        |«      k7  rŒ¶|jA                  tC        |‰!«      «      }t%        ˆ"fd
„|D «       «      jA                  tC        |‰!«      «      }tE        d„ |D «       «      }d}tG        ||«      D ]M  \  }}|jI                  |«      }|�t;        |t<        «      rd} n#t;        |t        «      sJ ‚||jJ                  z  }ŒO |dk(  r�Œut        ||z
  «      t        k  s�ŒŒ|s|jM                  ‰!«       �Œ¡tO        ˆ!fd„|D «       «      }|r�Œ¹|jM                  ‰!«       �ŒÌ |D �cg c]  }tC        ||«      ‘Œ } }| S c c}w c c}w c c}w c c}}w c c}}w c c}w c c}w )u±  Computes and returns the axes of symmetry for a planar face.

        The method determines potential symmetry axes by analyzing the faceâ€™s
        geometry:
        - It first validates that the face is non-empty and planar.
        - For faces with inner wires (holes), it computes the centroid of the
          holes and the face's overall center (COG).
            If the holes' centroid significantly deviates from the COG (beyond
            a specified tolerance), the symmetry axis is taken along the line
            connecting these points; otherwise, each holeâ€™s center is used to
            generate a candidate axis.
        - For faces without holes, candidate directions are derived by sampling
          midpoints along the outer wire's edges.
            If curved edges are present, additional candidate directions are
            obtained from an oriented bounding box (OBB) constructed around the
            face.

        For each candidate direction, the face is split by a plane (defined
        using the candidate direction and the faceâ€™s normal).  The top half of the face
        is then mirrored across this plane, and if the area of the intersection between
        the mirrored half and the bottom half matches the bottom halfâ€™s area within a
        small tolerance, the direction is accepted as an axis of symmetry.

        Returns:
            list[Axis]: A list of Axis objects, each defined by the face's
                center and a direction vector, representing the symmetry axes of
                the face.

        Raises:
            ValueError: If the face or its underlying representation is empty.
            ValueError: If the face is not planar.
        z.Can't determine axes_of_symmetry of empty facez/axes_of_symmetry only supports for planar facesT)ÚreverserË   r@   )rã   ç      à?g      ð?)ÚoriginÚx_dirÚz_dir)Úkeepc              3  ó@   •K  — | ]  }|j                  ‰«      –— Œ y ­wrÌ   )Úmirror)Ú.0r¡   Úsplit_planes     €r_   Ú	<genexpr>z(Face.axes_of_symmetry.<locals>.<genexpr>×  s   øè ø€ ð )Ù/7¨!�—‘˜×%©xùs   ƒc              3  ó4   K  — | ]  }|j                   –— Œ y ­wrÌ   )rå   ©rð   r¡   s     r_   rò   z(Face.axes_of_symmetry.<locals>.<genexpr>Û  s   è ø€ Ð:©k¨˜aŸf�f©kùs   ‚rã   ç      ð¿c              3  óT   •K  — | ]  }|j                  ‰«      d t        z   k  –— Œ! y­w)éÿÿÿÿN)Údotr7   )rð   ÚdÚ	cross_dirs     €r_   rò   z(Face.axes_of_symmetry.<locals>.<genexpr>î  s'   øè ø€ ð #ÙCP¸a˜Ÿ™˜iÓ(¨2´	©>Õ9Á=ùs   ƒ%()(rv   rw   Úis_planar_faceÚcenterr©   rÉ   rh   Úcombined_centerÚabsr7   Ú
normalizedrÈ   r»   Ú	filter_byr3   ÚLINEr;   ÚcornersrE   ÚrangerB   Ú	make_linerÕ   r<   Úcrossr¸   r4   ÚBOTHÚtyperÓ   ÚlistrÒ   Úsort_byr8   Úsumr–   Ú	intersectrå   ÚaddÚany)#r^   Úcogr¥   Úshape_inner_wiresrß   Ú
hole_facesÚholes_centroidÚ
cross_dirsr¡   Úcurved_edgesÚshape_edgesÚobbr  rž   Ú	obb_edgesÚeÚpÚ
mid_pointsÚ	mid_pointÚsymmetry_dirsÚtopÚbottomÚtop_listÚbottom_listÚtop_flipped_listÚbottom_areaÚintersect_areaÚflipped_faceÚbottom_faceÚintersectionÚoppositerù   Úsymmetry_axesrú   rñ   s#                                    @@r_   Úaxes_of_symmetryzFace.axes_of_symmetryx  sí  ù€ ðD �<‰<ÐÜÐMÓNÐNà×"Ò"ÜÐNÓOÐOà�k‰k‹mˆØ—‘Ó!ˆØ ×,Ñ,Ó.ÐÙÙ+<Ó=Ñ+< aœ$˜q�'Ð+<ˆJÐ=Ü!×1Ñ1°*Ó=ˆNô �> CÑ'Ó(¬9Ò4Ø-°Ñ3×?Ñ?ÓAÐB’
ñ HRÓRÁzÀ!˜qŸx™x›z¨CÑ/×;Ñ;Õ=Àz�
ÒRð —‘Ó!×'Ñ'Ó)×3Ñ3´H·M±MÈ4Ð3ÓPð ð Ÿ/™/Ó+×1Ñ1Ó3ˆKÙÜ& tÓ,�ØŸ+™+�Ü%ÜOTÐUVÌxÓXÉxÈ!”T—^‘^ G¨A¡J°¸¸Q¹À!¹Ñ0DÕEÈxÑXó�	ð $/°Ò#:ôÙ#:˜aÃO¸q�A˜“EÀO�EÐ#:ð ò ñ .9ÔR©[¨Ã/¸Q˜a !›eÀ/˜e¨[�
ÑRÙJTÓUÉ*¸Y˜9 s™?×6Ñ6Õ8È*ˆJÐUä%(£UˆÜ#ˆIäØØØ—o‘o fÓ-ôˆKð Ÿ*™* [´t·y±y˜*ÓA‰KˆC�ä�C‹yœD ›LÒ(Øàˆ{˜f˜nØä ¬
°3¼Ô(=¡ÀCÀ5ÓIˆHÜ#¬j¸¼dÔ.C¡FÈ&ÈÓRˆKä�8‹}¤ KÓ 0Ò0Øà%×-Ñ-¬d°3¸	Ó.BÓCˆKÜ(ó )Ù/7ó)ó  ç‰g”d˜3 	Ó*Ó+ð ô Ñ:©kÓ:Ó:ˆKØ ˆNÜ-0Ð1AÀ;Ö-OÑ)�˜kØ+×5Ñ5°kÓB�ØÐ'¬:°lÄDÔ+IØ%)�NÙä% l´DÔ9Ð9Ð9Ø" l×&7Ñ&7Ñ7‘Nð .Pð  Ò%Ùô �> KÑ/Ó0´9Ô<Ù$Ø!×%Ñ% iÖ0ä"ó #ÙCPó#ó  �Hó $Ø%×)Ñ)¨)Ö4ðe $ñh 0=Ó=©}¨!œ˜c 1�¨}ˆÐ=ØÐùòc >ùò Sùò Yùóùó SùÚUùòn >s*   Á'O/Â?(O4Å1)O9Æ)O>ÇPÇP
ÏPc                ór   — | j                  dd«      }t        || j                  |«      ¬«      j                  S )zLocation at the center of faceré   ©rì   )Úposition_atr<   r©   Úlocation)r^   rê   s     r_   Úcenter_locationzFace.center_location÷  s2   € ð ×!Ñ! # sÓ+ˆÜ�V 4§>¡>°&Ó#9Ô:×CÑCÐCra   c                óP  — d}| j                   �rt        | «      j                  | «      }|j                  «       }t	        d„ |D «       «      rÊ|j                  «       }d}t        |«      dk(  rªg }|D ]b  }|j                  |D �cg c]  }||j                  «       v sŒ|‘Œ c}«       |D ��	cg c]!  }|D �	cg c]  }	|	j                  d«      ‘Œ c}	‘Œ# }
}}	Œd t	        d„ 
D «       «      r/d}t        |j                  t        j                  «      «      dk(  rd	}|S c c}w c c}	w c c}	}w )
zgeometry of planar faceNc              3  óV   K  — | ]!  }|j                   t        j                  k(  –— Œ# y ­wrÌ   )Ú	geom_typer3   r  )rð   r  s     r_   rò   z Face.geometry.<locals>.<genexpr>  s   è ø€ ÐI¹°A�1—;‘;¤(§-¡-Õ/¹ùs   ‚')ÚPOLYGONrË   r   c              3  óP   K  — | ]  }|d    j                  |d   «      dk(  –— Œ  y­w)r   r@   éZ   N)Ú	get_angle)rð   Úedge_directionss     r_   rò   z Face.geometry.<locals>.<genexpr>  s2   è ø€ ð á/C˜Oð (¨Ñ*×4Ñ4°_ÀQÑ5GÓHÈBÕNÙ/Cùs   ‚$&Ú	RECTANGLEr@   ÚSQUARE)Ú	is_planarr<   r�   r»   Úallr¹   rÒ   r‘   Ú
tangent_atÚgroup_byr5   ÚLENGTH)r^   r£   Ú	flat_faceÚflat_face_edgesÚflat_face_verticesÚ
edge_pairsrº   r  Úpairr¼   Úedge_pair_directionss              r_   ÚgeometryzFace.geometryý  s(  € ð ˆØ�>‹>Ü# D›k×9Ñ9¸$Ó?ˆIØ'Ÿo™oÓ/ˆOÜÑI¹ÓIÔIØ%.×%7Ñ%7Ó%9Ð"Ø"�Ü�Ó'¨1Ò,Ø35�JÛ"4˜Ø"×)Ñ)Ù(7ÓR© 1¸6ÀQÇZÁZÃ\Ò;QšQ¨ÑRôñ OYô0ÙNXÀd¹DÓA¹D°D˜TŸ_™_¨QÕ/¸DÓAÈjð -ò 0ð	 #5ô ñ á/Cóô ð "-˜Ü˜×7Ñ7¼¿¹ÓFÓGÈ1ÒLØ%-˜Fàˆùò Sùò Bùó0s$   ÂD
ÂD
Â*	D"Â3DÃD"ÄD"c                ó   — | j                   S )z=Is the face planar even though its geom_type may not be PLANE)rû   r]   s    r_   r8  zFace.is_planar  s   € ð ×"Ñ"Ð"ra   c                óî   — d}| j                   rft        | «      j                  | «      }|j                  «       j	                  t
        j                  «      }|d   j                  |d   j                  z
  }|S )zlength of planar faceNr÷   r   )r8  r<   r�   r¹   r	  r8   ÚX©r^   r£   r=  Úface_verticess       r_   ÚlengthzFace.length  óf   € ð ˆØ�>Š>ä˜d›×3Ñ3°DÓ9ˆIØ%×.Ñ.Ó0×8Ñ8¼¿¹Ó@ˆMØ" 2Ñ&×(Ñ(¨=¸Ñ+;×+=Ñ+=Ñ=ˆFØˆra   c                óØ   — | j                   t        j                  t        j                  fv r>t	        | j                  «       «      t        k7  r| j                  «       j                  «       S y)z9Return the radius of a cylinder or sphere, otherwise NoneN)r0  r3   ÚCYLINDERÚSPHEREr  Úgeom_adaptorr   ÚRadiusr]   s    r_   ÚradiuszFace.radius*  sQ   € ð �N‰Nœx×0Ñ0´(·/±/ÐBÑBÜ�T×&Ñ&Ó(Ó)Ô-KÒKà×$Ñ$Ó&×-Ñ-Ó/Ð/àra   c                óè   — | j                   t        j                  k(  rUt        | j	                  «       «      t
        k7  r5t        | j	                  «       j                  «       j                  «       «      S y)z%Get the rotational axis of a cylinderN)r0  r3   rL  r  rN  r   r8   ÚCylinderr]   s    r_   Úrotational_axiszFace.rotational_axis5  sV   € ð �N‰Nœh×/Ñ/Ò/Ü�T×&Ñ&Ó(Ó)Ô-KÒKä˜×)Ñ)Ó+×4Ñ4Ó6×;Ñ;Ó=Ó>Ð>àra   c                 ó   — y)z6volume - the volume of this Face, which is always zerorã   r\   r]   s    r_   ÚvolumezFace.volume@  s   € ð ra   c                óî   — d}| j                   rft        | «      j                  | «      }|j                  «       j	                  t
        j                  «      }|d   j                  |d   j                  z
  }|S )zwidth of planar faceNr÷   r   )r8  r<   r�   r¹   r	  r8   ÚYrG  s       r_   Úwidthz
Face.widthE  rJ  ra   c                óf   — t        t        j                  t        |j                  |«      «      «      S )a/  extrude

        Extrude an Edge into a Face.

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

        Raises:
            ValueError: Unsupported class
            RuntimeError: Generated invalid result

        Returns:
            Face: extruded shape
        )rh   r*   ÚFace_srM   rv   rr   s      r_   rt   zFace.extrudeR  s$   € ô  ”F—M‘MÔ"7¸¿¹ÀYÓ"OÓPÓQÐQra   c           	     óŒ  — t        |«      dk  st        |d   «      dk  rt        d«      ‚t        |«      dkD  st        |d   «      dkD  rt        d«      ‚|r?t        |«      t        |«      k7  st        |d   «      t        |d   «      k7  rt        d«      ‚t        dt        |«      dt        |d   «      «      }t        |«      D ]H  \  }}t        |«      D ]5  \  }}|j	                  |dz   |dz   t        |«      j                  «       «       Œ7 ŒJ |rxt        dt        |«      dt        |d   «      «      }t        |«      D ]:  \  }}	t        |	«      D ]'  \  }}
|j	                  |dz   |dz   t        |
«      «       Œ) Œ< t        ||«      }nt        |«      } | t        |t        j                  «       «      j                  «       «      S )u  make_bezier_surface

        Construct a BÃ©zier surface from the provided 2d array of points.

        Args:
            points (list[list[VectorLike]]): a 2D list of control points
            weights (list[list[float]], optional): control point weights. Defaults to None.

        Raises:
            ValueError: Too few control points
            ValueError: Too many control points
            ValueError: A weight is required for each control point

        Returns:
            Face: a potentially non-planar face
        r[   r   z9At least two control points must be provided (start, end)é   z*The maximum number of control points is 25z0A weight must be provided for each control pointr@   )rÒ   rw   r'   r”   ÚSetValuer=   r•   r&   r²   r   r   r    ÚConfusion_srh   )rk   ÚpointsÚweightsÚpoints_rž   Ú
row_pointsÚjÚpointÚweights_Úrow_weightsÚweightÚbeziers               r_   Úmake_bezier_surfacezFace.make_bezier_surfaced  s˜  € ô, ˆv‹;˜Š?œc &¨¡)›n¨qÒ0ÜØKóð ô ˆv‹;˜Òœs 6¨!¡9›~°Ò2ÜÐIÓJÐJÙÜ�‹Kœ3˜w›<Ò'¬3¨v°a©y«>¼SÀÈÁ»_Ò+LäÐOÓPÐPä% a¬¨V«°a¼¸VÀA¹Y»ÓHˆÜ& vÖ.‰MˆAˆzÜ% jÖ1‘��5Ø× Ñ   Q¡¨¨A©¬v°e«}×/CÑ/CÓ/EÕFñ 2ð /ñ Ü,¨Q´°G³¸aÄÀWÈQÁZÃÓQˆHÜ"+¨GÖ"4‘��;Ü!*¨;Ö!7‘I�A�vØ×%Ñ% a¨!¡e¨Q°©U´E¸&³MÕBñ "8ð #5ô (¨°Ó:‰Fä'¨Ó0ˆFáÔ*¨6´9×3HÑ3HÓ3JÓK×PÑPÓRÓSÐSra   c                óX   — t        |j                  «      j                  «       } | |«      S )z/Create a unlimited size Face aligned with plane©r   rv   rh   )rk   ÚplaneÚ	pln_shapes      r_   Ú
make_planezFace.make_plane•  s%   € ô ,¨E¯M©MÓ:×?Ñ?ÓAˆ	Ù�9‹~Ðra   c                ó|   — t        |j                  | dz  |dz  | dz  |dz  «      j                  «       } | |«      S )aT  make_rect

        Make a Rectangle centered on center with the given normal

        Args:
            width (float, optional): width (local x).
            height (float, optional): height (local y).
            plane (Plane, optional): base plane. Defaults to Plane.XY.

        Returns:
            Face: The centered rectangle
        ré   rk  )rk   rX  Úheightrl  rm  s        r_   Ú	make_rectzFace.make_rectž  sG   € ô ,Ø�M‰M˜E˜6 C™<¨°©°v°gÀ±mÀVÈcÁ\ó
ç
‰$‹&ð 	ñ �9‹~Ðra   c                ó~  — t        |t        «      rt        |«      n|}|r|D �cg c]  }t        |«      ‘Œ }}nd}t	        dddddddd	d
d¬«
      }t        |t
        «      r|j                  «       }n9t        |t        «      rt        d„ |D «       «      rt        |«      }nt        d«      ‚|D ]"  }|j                  |j                  t        «       Œ$ 	 |j                  «        t        |j                  «       «      }	|rV|D ]'  }|j                  t+        |j-                  «       Ž «       Œ) 	 |j                  «        t        |j                  «       «      }	|rQt/        |	j                  «      }|D ]  }|j                  |j                  «       Œ 	 t        |j                  «       «      }	|	j1                  «       }	|	j3                  «       st)        d«      ‚|	S c c}w # t         t"        t$        t&        f$ r}
t)        d«      |
‚d}
~
ww xY w# t"        $ r}
t)        d«      |
‚d}
~
ww xY w# t"        $ r}
t)        d«      |
‚d}
~
ww xY w)aP  Create Non-Planar Face

        Create a potentially non-planar face bounded by exterior (wire or edges),
        optionally refined by surface_points with optional holes defined by
        interior_wires.

        Args:
            exterior (Union[Wire, list[Edge]]): Perimeter of face
            surface_points (list[VectorLike], optional): Points on the surface that
                refine the shape. Defaults to None.
            interior_wires (list[Wire], optional): Hole(s) in the face. Defaults to None.

        Raises:
            RuntimeError: Internal error building face
            RuntimeError: Error building non-planar face with provided surface_points
            RuntimeError: Error adding interior hole
            RuntimeError: Generated face is invalid

        Returns:
            Face: Potentially non-planar face
        Né   é   r[   Fgñhãˆµøä>g-Cëâ6?ç{®Gáz„?gš™™™™™¹?é   é	   )
ÚDegreeÚ
NbPtsOnCurÚNbIterÚAnisotropieÚTol2dÚTol3dÚTolAngÚTolCurvÚMaxDegÚMaxSegmentsc              3  ó<   K  — | ]  }t        |t        «      –— Œ y ­wrÌ   )rÓ   rB   )rð   Úos     r_   rò   z$Face.make_surface.<locals>.<genexpr>ì  s   è ø€ ð 4
Ù)1 AŒJ�qœ$×©ùs   ‚z(exterior must be a Wire or list of Edgesz5Error building non-planar face with provided exteriorz;Error building non-planar face with provided surface_pointsúJError adding interior hole in non-planar face with provided interior_wiresznon planar face is invalid)rÓ   r   r  r=   r   rC   r»   r9  rE   rw   ÚAddrv   r   ÚBuildrh   rD   r"   r%   r#   r$   ÚRuntimeErrorr0   Úto_tupler   ÚfixÚis_valid)rk   ÚexteriorÚsurface_pointsÚinterior_wiresr  Úsurface_point_vectorsÚsurfaceÚoutside_edgesr¼   Úsurface_faceÚerrrd  Úmakeface_objectÚwires                 r_   Úmake_surfacezFace.make_surface²  s-  € ô8 &0°¼(Ô%C”4˜”>ÈˆáÙ8FÓ$G¹°1¤V¨A¥Y¸Ð!Ñ$Gà$(Ð!ô ,ààØØààààààô%
ˆô( �h¤Ô%Ø$ŸN™NÓ,‰MÜ˜¤(Ô+´ñ 4
Ù)1ó4
ô 1
ô & hÓ/‰MäÐGÓHÐHã!ˆDØ�K‰K˜Ÿ™¤jÕ1ð "ð	Ø�M‰MŒOÜ §¡£Ó0ˆLñ !Û.�Ø—‘œF E§N¡NÓ$4Ð5Õ6ð /ðØ—‘”Ü# G§M¡M£OÓ4�ñ Ü5°l×6JÑ6JÓKˆOÛ&�Ø×#Ñ# D§L¡LÕ1ð 'ðÜ# O×$8Ñ$8Ó$:Ó;�ð $×'Ñ'Ó)ˆØ×$Ñ$Ô&ÜÐ;Ó<Ð<àÐùòY %HøôR ÜÜ!Ü&ð	
ò 	ô ØGóàðûð	ûô #ò Ü"ØQóàðûðûô #ò Ü"Ø`óàðûðúsM   ¤GÃ)G Ä*)H ÆH" ÇHÇ1G=Ç=HÈ	HÈHÈHÈ"	H<È+H7È7H<c           	     óò  — t        dt        |«      dt        |d   «      «      }t        |«      D ]H  \  }}t        |«      D ]5  \  }	}
|j                  |dz   |	dz   t	        |
«      j                  «       «       Œ7 ŒJ |rt        |g|¢­||dœŽ}nt        ||||¬«      }|j                  «       st        d«      ‚|j                  «       } | t        |t        j                  «       «      j                  «       «      S )až  make_surface_from_array_of_points

        Approximate a spline surface through the provided 2d array of points.
        The first dimension correspond to points on the vertical direction in the parameter
        space of the face. The second dimension correspond to points on the horizontal
        direction in the parameter space of the face. The 2 dimensions are U,V dimensions
        of the parameter space of the face.

        Args:
            points (list[list[VectorLike]]): a 2D list of points, first dimension is V
                parameters second is U parameters.
            tol (float, optional): tolerance of the algorithm. Defaults to 1e-2.
            smoothing (Tuple[float, float, float], optional): optional tuple of
                3 weights use for variational smoothing. Defaults to None.
            min_deg (int, optional): minimum spline degree. Enforced only when
                smoothing is None. Defaults to 1.
            max_deg (int, optional): maximum spline degree. Defaults to 3.

        Raises:
            ValueError: B-spline approximation failed

        Returns:
            Face: a potentially non-planar face defined by points
        r@   r   )ÚDegMaxÚTol3D)ÚDegMinr—  r˜  zB-spline approximation failed)r'   rÒ   r”   r]  r=   r•   r   ÚIsDonerw   ÚSurfacer   r    r^  rh   )rk   r_  ÚtolÚ	smoothingÚmin_degÚmax_degra  rž   Ú	point_rowrc  rd  Úspline_builderÚspline_geoms                r_   Ú!make_surface_from_array_of_pointsz&Face.make_surface_from_array_of_points  sô   € ôB & a¬¨V«°a¼¸VÀA¹Y»ÓHˆä% fÖ-‰LˆAˆyÜ% iÖ0‘��5Ø× Ñ   Q¡¨¨A©¬v°e«}×/CÑ/CÓ/EÕFñ 1ð .ñ Ü;ØðØ#ñØ,3¸3ò‰Nô <Ø °¸sôˆNð ×$Ñ$Ô&ÜÐ<Ó=Ð=à$×,Ñ,Ó.ˆáÔ*¨;¼	×8MÑ8MÓ8OÓP×UÑUÓWÓXÐXra   c                 ó   — y rÌ   r\   )rk   Úedge1Úedge2s      r_   Úmake_surface_from_curveszFace.make_surface_from_curvesV  ó   € ð
 	ra   c                 ó   — y rÌ   r\   )rk   Úwire1Úwire2s      r_   r§  zFace.make_surface_from_curves]  r¨  ra   c                óè  — d\  }}|r:t        |«      dk7  st        |d   «      t        |d   «      urt        d«      ‚|\  }}|j                  d|«      }|j                  d|«      }|j                  d|«      }|j                  d	|«      }|r+t	        d
dj                  |j                  «       «      › �«      ‚t        |t        t        f«      rt        |t        t        f«      st        d«      ‚t        |t        «      r;| j                  t        j                  |j                  |j                  «      «      }|S | j                  t        j                  |j                  |j                  «      «      }|S )ar  make_surface_from_curves

        Create a ruled surface out of two edges or two wires. If wires are used then
        these must have the same number of edges.

        Args:
            curve1 (Union[Edge,Wire]): side of surface
            curve2 (Union[Edge,Wire]): opposite side of surface

        Returns:
            Face: potentially non planar surface
        ©NNr[   r   r@   z>Both curves must be of the same type (both Edge or both Wire).r¥  r¦  rª  r«  zUnexpected argument(s): rÎ   )rÒ   r  Ú	TypeErrorÚpoprw   rÔ   rÖ   rÓ   rB   rC   ro   r   ÚShell_srv   rZ  )rk   rÛ   rÜ   Úcurve1Úcurve2Úreturn_values         r_   r§  zFace.make_surface_from_curvesd  sA  € ð $‰ˆ�ÙÜ�4‹y˜AŠ~¤ d¨1¡g£´d¸4À¹7³mÑ!CÜØTóð ð "‰NˆF�Fà—‘˜G VÓ,ˆØ—‘˜G VÓ,ˆØ—‘˜G VÓ,ˆØ—‘˜G VÓ,ˆñ ÜÐ7¸¿	¹	À&Ç+Á+Ã-Ó8PÐ7QÐRÓSÐSä˜&¤4¬ ,Ô/´zÀ&Ì4ÔQUÈ,Ô7WÜØPóð ô �fœdÔ#ØŸ8™8¤H×$4Ñ$4°V·^±^ÀVÇ^Á^Ó$TÓUˆLð Ðð Ÿ8™8¤H§O¡O°F·N±NÀFÇNÁNÓ$SÓTˆLØÐra   c           
     ó   — t        |D �cg c]  }|j                  ‘Œ c}«      }t        |«      }g }|D ]Ã  }t        |t        «      r%|j                  t        t        |«      g«      «       Œ8t        |t        «      r)|j                  t        |«      j                  «       «       Œqt        |t        «      r,|j                  t        d„ t        |d«      D «       «      «       Œ­t        dt        |«      › d�«      ‚ |S c c}w )aG  sew faces

        Group contiguous faces and return them in a list of ShapeList

        Args:
            faces (Iterable[Face]): Faces to sew together

        Raises:
            RuntimeError: OCCT SewedShape generated unexpected output

        Returns:
            list[ShapeList[Face]]: grouped contiguous faces
        c              3  ó2   K  — | ]  }t        |«      –— Œ y ­wrÌ   )rh   rô   s     r_   rò   z!Face.sew_faces.<locals>.<genexpr>ª  s   è ø€ ð Ù)R Aœ˜QŸÑ)Rùs   ‚rh   zSewedShape returned a z which was unexpected)rI   rv   rH   rÓ   r+   r‘   rE   rh   r-   rj   r„   r.   rK   r‡  r  )rk   r„   r¡   Úsewed_shapeÚtop_level_shapesÚ
sewn_facesÚtop_level_shapes          r_   Ú	sew_faceszFace.sew_facesŽ  sì   € ô  (¹EÓ(B¹E°q¨¯«¸EÑ(BÓCˆÜ6°{ÓCÐØ&(ˆ
ó  0ˆOÜ˜/¬;Ô7Ø×!Ñ!¤)¬T°/Ó-BÐ,CÓ"DÕEÜ˜O¬\Ô:Ø×!Ñ!¤%¨Ó"8×">Ñ">Ó"@ÕAÜ˜O¬\Ô:Ø×!Ñ!Üñ Ü)9¸/È6Ô)Róó õô #Ø,¬T°/Ó-BÐ,CÐCXÐYóð ð  0ð  Ðùò+ )Cs   ŠC;c                ó.  — t        |j                  «       «      dk7  st        |j                  «       «      dk7  rt        d«      ‚t        |j	                  «       g«      }t        |j	                  «       g«      }t        |j                  «      }|j                  |j                  dd«       |j                  t        j                  |   «       |j                  «        t        |j                  «       «      }t        j                  r|j                  «       }|S )aO  sweep

        Sweep a 1D profile along a 1D path. Both the profile and path must be composed
        of only 1 Edge.

        Args:
            profile (Union[Curve,Edge,Wire]): the object to sweep
            path (Union[Curve,Edge,Wire]): the path to follow when sweeping
            transition (Transition, optional): handling of profile orientation at C1 path
                discontinuities. Defaults to Transition.TRANSFORMED.

        Raises:
            ValueError: Only 1 Edge allowed in profile & path

        Returns:
            Face: resulting face, may be non-planar
        r@   z&Use Shell.sweep for multi Edge objectsF)rÒ   r»   rw   rC   r¼   r   rv   r…  ÚSetTransitionModerD   Ú_transModeDictr†  rh   rF   Úclean©rk   ÚprofileÚpathÚ
transitionÚbuilderr£   s         r_   Úsweepz
Face.sweepµ  sÅ   € ô: ˆw�}‰}‹Ó 1Ò$¬¨D¯J©J«LÓ(9¸QÒ(>ÜÐEÓFÐFÜ˜Ÿ™›Ð'Ó(ˆÜ�T—Y‘Y“[�MÓ"ˆÜ-¨d¯l©lÓ;ˆØ�‰�G—O‘O U¨EÔ2Ø×!Ñ!¤%×"6Ñ"6°zÑ"BÔCØ�‰ŒÜ�g—m‘m“oÓ&ˆÜ�?Š?Ø—\‘\“^ˆFàˆra   c                ód  — |t         j                  k(  s|t         j                  k(  rQ| j                  rEt	        «       }t        j                  | j                  |«       |j                  «       }t#        |«      S |t         j                  k(  r)| j                  «       j                  «       }t#        |«      S |t         j                  k(  r`| j                  «       \  }}}}d||z   z  }d||z   z  }	t        «       }t        «       }
t        | j                  «      j!                  ||	||
«       t#        «      S )zÞCenter of Face

        Return the center based on center_of

        Args:
            center_of (CenterOf, optional): centering option. Defaults to CenterOf.GEOMETRY.

        Returns:
            Vector: center
        ré   )r2   ÚMASSÚGEOMETRYr8  r   r   ÚSurfaceProperties_srv   ÚCentreOfMassÚBOUNDING_BOXÚbounding_boxrü   Ú
_uv_boundsr0   r1   r   ÚNormalr=   )r^   Ú	center_ofÚ
propertiesÚcenter_pointÚu_val0Úu_val1Úv_val0Úv_val1Úu_valÚv_valr¥   s              r_   rü   zFace.centerâ  s  € ð œŸ™Ò&Øœ×*Ñ*Ò*¨t¯~ª~ä%›ˆJÜ×)Ñ)¨$¯,©,¸
ÔCØ%×2Ñ2Ó4ˆLô �lÓ#Ð#ð œ(×/Ñ/Ò/Ø×,Ñ,Ó.×5Ñ5Ó7ˆLô �lÓ#Ð#ð œ(×+Ñ+Ò+Ø-1¯_©_Ó->Ñ*ˆF�F˜F FØ˜6 F™?Ñ+ˆEØ˜6 F™?Ñ+ˆEä!›8ˆLÜ“XˆFÜ˜4Ÿ<™<Ó(×/Ñ/°°u¸lÈFÔSä�lÓ#Ð#ra   c                óÄ  — |}t        | j                  «      }t        «       }t        j                  | j                  t
        j                  t
        j                  |«       |D ]¶  }|j                  |j                  «      }	t        |	j                  «       «      t        |	j                  «       «      f}
t        j                  ||
«      \  }}|j                  t        j                   |j                  «      t        j                   |j                  «      ||«       Œ¸ |j#                  «        | j$                  j'                  |j)                  «       «      j+                  «       S )a  Apply 2D chamfer to a face

        Args:
            distance (float): chamfer length
            distance2 (float): chamfer length
            vertices (Iterable[Vertex]): vertices to chamfer
            edge (Edge): identifies the side where length is measured. The vertices must be
                part of the edge

        Raises:
            ValueError: Cannot chamfer at this location
            ValueError: One or more vertices are not part of edge

        Returns:
            Face: face with a chamfered corner(s)

        )r   rv   r)   r(   ÚMapShapesAndAncestors_src   rd   re   ÚFindFromKeyrB   ÚFirstÚLastrC   Úorder_chamfer_edgesÚ
AddChamferr*   ÚEdge_sr†  rá   ro   rD   r‰  )r^   r�   Ú	distance2r¹   r¼   Úreference_edgeÚchamfer_builderÚvertex_edge_mapÚvÚ	edge_listr»   r¥  r¦  s                r_   Ú
chamfer_2dzFace.chamfer_2d  s  € ð0 ˆä4°T·\±\ÓBˆäCÓEˆÜ×&Ñ&Ø�L‰Lœ"×*Ñ*¬B¯N©N¸Oô	
ó ˆAØ'×3Ñ3°A·I±IÓ>ˆIô ˜)Ÿ/™/Ó+Ó,¬d°9·>±>Ó3CÓ.DÐEˆEä×3Ñ3°NÀEÓJ‰LˆE�5à×&Ñ&Ü—‘˜eŸm™mÓ,Ü—‘˜eŸm™mÓ,ØØõ	ð ð  	×ÑÔØ�~‰~×"Ñ" ?×#8Ñ#8Ó#:Ó;×?Ñ?ÓAÐAra   c                óä   — t        | j                  «      }|D ]  }|j                  |j                  |«       Œ  |j                  «        | j                  j                  |j                  «       «      S )zƒApply 2D fillet to a face

        Args:
          radius: float:
          vertices: Iterable[Vertex]:

        Returns:

        )r   rv   Ú	AddFilletr†  rá   ro   rD   )r^   rP  r¹   Úfillet_builderrº   s        r_   Ú	fillet_2dzFace.fillet_2d6  s\   € ô 4°D·L±LÓAˆãˆFØ×$Ñ$ V§^¡^°VÕ<ð ð 	×ÑÔà�~‰~×"Ñ" >×#7Ñ#7Ó#9Ó:Ð:ra   c                ó@   — t        j                  | j                  «      S )z%Return the Geom Surface for this Face)r	   Ú	Surface_srv   r]   s    r_   rN  zFace.geom_adaptorJ  s   € ä×"Ñ" 4§<¡<Ó0Ð0ra   c                óž   — | j                  «       }t        | j                  «       D �cg c]  }|j                  |«      rŒ|‘Œ c}«      S c c}w )z.Extract the inner or hole wires from this Face)rÈ   rE   r½   Úis_same)r^   Úouterrß   s      r_   rÉ   zFace.inner_wiresN  s<   € à—‘Ó!ˆä T§Z¡Z¤\ÓJ¡\ ¸¿¹À5Õ9Iš! \ÑJÓKÐKùÒJs
   ¨A
¿A
c                óH  — | j                  «       \  }}}}t        «       }t        «       }t        | j                  «      j                  ||||«       |j                  t        |«      «      xr7 dt        |j                  j                  t        |«      «      «      z
  t        k  S )z4Is this planar face coplanar with the provided planer@   )rÌ  r0   r1   r   rv   rÍ  Úcontainsr=   rþ   rì   rø   r7   )r^   rl  rÑ  Ú_u_val1rÓ  Ú_v_val1Úgp_pntr¥   s           r_   Úis_coplanarzFace.is_coplanarT  s‚   € à+/¯?©?Ó+<Ñ(ˆ�˜ Ü“ˆÜ“ˆÜ�t—|‘|Ó$×+Ñ+¨F°F¸FÀFÔKð �N‰Nœ6 &›>Ó*ò EØ”C˜Ÿ™Ÿ™¬¨v«Ó7Ó8Ñ8¼9ÑDð	
ra   c                óª   — t        | j                  «      }|j                  t        t	        |«      j                  «       Ž |«       |j                  «       S )a  Point inside Face

        Returns whether or not the point is inside a Face within the specified tolerance.
        Points on the edge of the Face are considered inside.

        Args:
          point(VectorLike): tuple or Vector representing 3D point to be tested
          tolerance(float): tolerance for inside determination. Defaults to 1.0e-6.
          point: VectorLike:
          tolerance: float:  (Default value = 1.0e-6)

        Returns:
          bool: indicating whether or not point is within Face

        )r   rv   ÚPerformr0   r=   rˆ  Ú	IsOnAFace)r^   rd  r˜   Úsolid_classifiers       r_   Ú	is_insidezFace.is_inside`  sD   € ô  7°t·|±|ÓDÐØ× Ñ ¤¬°«×)?Ñ)?Ó)AÐ!BÀIÔNØ×)Ñ)Ó+Ð+ra   c                óÚ   — | j                  ||«      }|€'t        || j                  |«      ¬«      }t	        |«      S t        |t        |«      | j                  |«      ¬«      }t	        |«      S )z$Location at the u/v position of facer*  )rë   rì   )r+  r<   r©   r=   r:   )r^   Úurã  rë   rê   Úplns         r_   Úlocation_atzFace.location_atx  sc   € ð ×!Ñ! ! QÓ'ˆØˆ=Ü˜ d§n¡n°VÓ&<Ô=ˆCô ˜‹}Ðô ˜¤f¨U£m¸4¿>¹>È&Ó;QÔRˆCÜ˜‹}Ðra   c                ó  — t        | j                  «      }|D ]  }|j                  |j                  «       Œ 	 t        |j                  «       «      }|j                  «       }|S # t        $ r}t        d«      |‚d}~ww xY w)aW  Make Holes in Face

        Create holes in the Face 'self' from interior_wires which must be entirely interior.
        Note that making holes in faces is more efficient than using boolean operations
        with solid object. Also note that OCCT core may fail unless the orientation of the wire
        is correct - use `Wire(forward_wire.wrapped.Reversed())` to reverse a wire.

        Example:

            For example, make a series of slots on the curved walls of a cylinder.

        .. image:: slotted_cylinder.png

        Args:
          interior_wires: a list of hole outline wires
          interior_wires: list[Wire]:

        Returns:
          Face: 'self' with holes

        Raises:
          RuntimeError: adding interior hole in non-planar face with provided interior_wires
          RuntimeError: resulting face is not valid

        r„  N)r   rv   r…  rh   r%   r‡  r‰  )r^   r�  r“  Úinterior_wirer‘  r’  s         r_   Ú
make_holeszFace.make_holesƒ  s…   € ô6 2°$·,±,Ó?ˆÛ+ˆMØ×Ñ × 5Ñ 5Õ6ð ,ð	Ü × 4Ñ 4Ó 6Ó7ˆLð $×'Ñ'Ó)ˆð Ðøô ò 	ÜØ\óàðûð	ús   ¹A$ Á$	A>Á-A9Á9A>c                 ó   — y)a  normal_at point on surface

        Args:
            surface_point (VectorLike, optional): a point that lies on the surface where
                the normal. Defaults to the center (None).

        Returns:
            Vector: surface normal direction
        Nr\   )r^   Úsurface_points     r_   r©   zFace.normal_at®  rÆ   ra   c                 ó   — y)aó  normal_at u, v values on Face

        Args:
            u (float): the horizontal coordinate in the parameter space of the Face,
                between 0.0 and 1.0
            v (float): the vertical coordinate in the parameter space of the Face,
                between 0.0 and 1.0
                Defaults to the center (None/None)

        Raises:
            ValueError: Either neither or both u v values must be provided

        Returns:
            Vector: surface normal direction
        Nr\   )r^   rû  rã  s      r_   r©   zFace.normal_atº  rÆ   ra   c                óÆ  — d\  }}}|rct        |d   t        «      r|d   }nt        |d   t        t        f«      r|d   }t	        |«      dk(  rt        |d   t        t        f«      r|d   }dj                  t        |j                  «       «      j                  g d¢«      «      }|rt        d|› �«      ‚|j                  d|«      }|j                  d	|«      }|j                  d
|«      }|€|dk  r|dk  rd\  }}n$|€"t        d„ ||fD «       «      dk(  rt        d«      ‚| j                  «       }|€&| j                  «       \  }}	}
}|||	z   z  }||
|z   z  }n6t        t        |«      j!                  «       |«      }|j#                  «       \  }}t%        «       }t'        «       }t)        | j*                  «      j-                  ||||«       t        |«      j/                  «       S )a0  normal_at

        Computes the normal vector at the desired location on the face.

        Args:
            surface_point (VectorLike, optional): a point that lies on the surface where the normal.
                Defaults to None.

        Returns:
            Vector: surface normal direction
        )Nrõ   rõ   r   r[   r@   rÎ   )r  rû  rã  rÏ   r  rû  rã  )ré   ré   c              3  ó&   K  — | ]	  }|d k(  –— Œ y­w)rõ   Nr\   )rð   rž   s     r_   rò   z!Face.normal_at.<locals>.<genexpr>í  s   è ø€ Ð*E¹f¸¨1°­9¹fùs   ‚z#Both u & v values must be specified)rÓ   r   r±   r²   rÒ   rÔ   rÕ   rÖ   r×   rw   rØ   r
  rN  rÌ  r   r=   r•   ÚLowerDistanceParametersr0   r1   r   rv   rÍ  rÿ   )r^   rÛ   rÜ   r  rû  rã  rÞ   r�  rÑ  rÒ  rÓ  rÔ  rÕ  rÖ  Ú	projectorró  r¥   s                    r_   r©   zFace.normal_atÌ  sÕ  € ð /Ñˆ�q˜!áÜ˜$˜q™'¤8Ô,Ø $ Q¡‘Ü˜D ™G¤c¬5 \Ô2Ø˜‘G�Ü�4‹y˜AŠ~¤*¨T°!©W´s¼E°lÔ"CØ˜‘G�à—y‘yÜ�—‘“Ó×)Ñ)Ò*EÓFó
ˆñ ÜÐ6°|°nÐEÓFÐFàŸ
™
 ?°MÓBˆØ�J‰J�s˜AÓˆØ�J‰J�s˜AÓˆØÐ  Q¨¢U¨q°1ªuØ‰DˆA‰qØÐ"¤sÑ*E¸qÀ!¹fÓ*EÓ'EÈÒ'JÜÐBÓCÐCð ×#Ñ#Ó%ˆàÐ Ø-1¯_©_Ó->Ñ*ˆF�F˜F FØ˜ &™Ñ)ˆEØ˜ &™Ñ)‰Eô 3Ü�}Ó%×,Ñ,Ó.°óˆIð %×<Ñ<Ó>‰LˆE�5ä“ˆÜ“ˆÜ�t—|‘|Ó$×+Ñ+¨E°5¸&À&ÔIä�f‹~×(Ñ(Ó*Ð*ra   c                óR   — t        t        j                  | j                  «      «      S )z)Extract the perimeter wire from this Face)rC   r   ÚOuterWire_srv   r]   s    r_   rÈ   zFace.outer_wire  s   € ä”I×)Ñ)¨$¯,©,Ó7Ó8Ð8ra   c                óä   — | j                  «       \  }}}}||||z
  z  z   }||||z
  z  z   }t        «       }	t        «       }
t        | j                  «      j                  |||	|
«       t        |	«      S )a…  position_at

        Computes a point on the Face given u, v coordinates.

        Args:
            u (float): the horizontal coordinate in the parameter space of the Face,
                between 0.0 and 1.0
            v (float): the vertical coordinate in the parameter space of the Face,
                between 0.0 and 1.0

        Returns:
            Vector: point on Face
        )rÌ  r0   r1   r   rv   rÍ  r=   )r^   rû  rã  rÑ  rÒ  rÓ  rÔ  rÕ  rÖ  ró  r¥   s              r_   r+  zFace.position_at	  st   € ð *.¯©Ó):Ñ&ˆ�˜ Ø˜˜f v™oÑ.Ñ.ˆØ˜˜f v™oÑ.Ñ.ˆä“ˆÜ“ˆÜ�t—|‘|Ó$×+Ñ+¨E°5¸&À&ÔIä�f‹~Ðra   c                ó>  — t        | |g«      }t        | j                  t        |«      |z  «      }t	        «       }t        |t        «      rt        d«      ‚t        |t        «      rLt        |f|j                  ft        «       «      }|j                  «       s{|j                  t        |«      «       n`|j                  «       D ]M  }t        |f|j                  ft        «       «      }t        |«      D ]  }|j                  t        |«      «       Œ ŒO |j!                  t#        | j%                  «       |«      «      }t	        «       }	|D ]T  }
t'        |
j)                  «       «      dk(  r%|
j+                  «       }|€Œ2|	j                  |«       ŒD|	j                  |
«       ŒV |	S )aþ  Project Face to target Object

        Project a Face onto a Shape generating new Face(s) on the surfaces of the object.

        A projection with no taper is illustrated below:

        .. image:: flatProjection.png
            :alt: flatProjection

        Note that an array of faces is returned as the projection might result in faces
        on the "front" and "back" of the object (or even more if there are intermediate
        surfaces in the projection path). faces "behind" the projection are not
        returned.

        Args:
            target_object (Shape): Object to project onto
            direction (VectorLike): projection direction

        Returns:
            ShapeList[Face]: Face(s) projected on target object ordered by distance
        z'projection to a vertex is not supportedr@   )rN   rM   rv   r=   rE   rÓ   rR   r®  rh   rQ   r   ÚIsNullr‘   r¯   rH   rj   r	  r8   rü   rÒ   r„   r€   )r^   Útarget_objectrs   Úmax_dimensionÚextruded_topods_selfÚintersected_shapesÚtopods_shapeÚtarget_shellÚtopods_shellÚprojected_shapesÚshapeÚ
shape_faces               r_   Úproject_to_shapezFace.project_to_shape!  ss  € ô0 +¨D°-Ð+@ÓAˆÜ4Ø�L‰Lœ& Ó+¨mÑ;ó 
Ðô 7@³kÐÜ�m¤VÔ,ÜÐEÓFÐFÜ�m¤TÔ*Ü*Ø%Ð'¨-×*?Ñ*?Ð)AÔCUÓCWóˆLð  ×&Ñ&Ô(Ø"×)Ñ)¬$¨|Ó*<Õ=à -× 4Ñ 4Ö 6�Ü.Ø)Ð+Ø!×)Ñ)Ð+Ü&Ó(ó �ô
 %@ÀÖ$M�LØ&×-Ñ-¬e°LÓ.AÕBñ %Nð !7ð 0×7Ñ7¼¸T¿[¹[»]ÈIÓ8VÓWÐÜ4=³KÐÛ'ˆEÜ�5—;‘;“=Ó! QÒ&Ø"ŸZ™Z›\�
ØÑ)Ø$×+Ñ+¨JÕ7à ×'Ñ'¨Õ.ð (ð  Ðra   c                ó¢   — | j                   €t        d«      ‚| j                  j                  t	        j
                  | j                   |«      «      S )zðto_arcs

        Approximate planar face with arcs and straight line segments.

        Args:
            tolerance (float, optional): Approximation tolerance. Defaults to 1e-3.

        Returns:
            Face: approximated face
        z!Cannot approximate an empty shape)rv   rw   rá   ro   r   ÚConvertFace_s)r^   r˜   s     r_   Úto_arcszFace.to_arcs\  s@   € ð �<‰<ÐÜÐ@ÓAÐAà�~‰~×"Ñ"¤8×#9Ñ#9¸$¿,¹,È	Ó#RÓSÐSra   c                ó4  — | j                   €t        d«      ‚| j                  «       x}s| S t        j                  | «      }t        «       }|D ]  }|j                  |j                   «       Œ t        |j                  | j                   «      «      }||_         |S )z°without_holes

        Remove all of the holes from this face.

        Returns:
            Face: A new Face instance identical to the original but without any holes.
        z&Cannot remove holes from an empty face)	rv   rw   rÉ   rx   ry   r   ÚRemoverG   ÚApply)r^   rÉ   ÚholelessÚreshaperÚ	hole_wireÚmodified_shapes         r_   rä   zFace.without_holesl  s‰   € ð �<‰<ÐÜÐEÓFÐFà#×/Ñ/Ó1Ð1�Ð1ØˆKä—=‘= Ó&ˆÜ$Ó&ˆÛ$ˆIØ�O‰O˜I×-Ñ-Õ.ð %ä! (§.¡.°·±Ó">Ó?ˆØ)ˆÔØˆra   c                óp   — | j                  «       rt        j                  dd¬«       | j                  «       S )z?Return the outerwire, generate a warning if inner_wires presentz!Found holes, returning outer_wirer[   )Ú
stacklevel)rÉ   ÚwarningsÚwarnrÈ   r]   s    r_   r”  z	Face.wire‚  s/   € à×ÑÔÜ�M‰MØ3Øõð �‰Ó Ð ra   c                ó@   — t        j                  | j                  «      S )z,Return the u min, u max, v min, v max values)r   Ú
UVBounds_srv   r]   s    r_   rÌ  zFace._uv_bounds‹  s   € ä×#Ñ# D§L¡LÓ1Ð1ra   )rÐ   NN)rl   r+   rÂ   ÚstrrÃ   úColor | NonerÄ   úCompound | None©NrÐ   NN)
rÈ   rC   rÉ   úIterable[Wire] | NonerÂ   r(  rÃ   r)  rÄ   r*  )rÛ   r   rÜ   r   ©r°   r²   )r°   z
list[Axis])r°   r:   )r°   z
None | str)r°   Úbool)r°   zNone | float)r°   zNone | Axis)rl   rB   rs   r>   r°   rh   rÌ   )r_  úlist[list[VectorLike]]r`  zlist[list[float]] | Noner°   rh   )rl  r<   r°   rh   )rX  r²   rp  r²   rl  r<   r°   rh   r­  )r‹  zWire | Iterable[Edge]rŒ  zIterable[VectorLike] | Noner�  r,  r°   rh   )ru  Nr@   rs  )r_  r/  rœ  r²   r�  z!tuple[float, float, float] | Nonerž  r±   rŸ  r±   r°   rh   )r¥  rB   r¦  rB   r°   rh   )rª  rC   r«  rC   r°   rh   )r°   rh   )r„   zIterable[Face]r°   zlist[ShapeList[Face]])rÀ  úCurve | Edge | WirerÁ  r0  r°   rh   )rÎ  r2   r°   r=   )
r�   r²   rß  r²   r¹   úIterable[Vertex]r¼   zEdge | Noner°   rh   )rP  r²   r¹   r1  r°   rh   )r°   r   )r°   zShapeList[Wire])rl  r<   r°   r.  )g�íµ ÷Æ°>)rd  r>   r˜   r²   r°   r.  )rû  r²   rã  r²   rë   úVectorLike | Noner°   r:   )r�  ú
list[Wire]r°   rh   )r  r2  r°   r=   )rû  r²   rã  r²   r°   r=   ©r°   r=   )r°   rC   )r  rD   rs   r>   r°   zShapeList[Face | Shell])gü©ñÒMbP?)r˜   r²   r°   rh   )r°   z!tuple[float, float, float, float])4r³   r´   rµ   r¶   Úorderr   rÅ   r¾   ræ   r(  r-  rC  r8  rI  rP  rS  rU  rX  r¿   rt   ri  r<   ÚXYrn  rq  r•  r£  r§  rº  r6   ÚTRANSFORMEDrÄ  r2   rÇ  rü   rå  ré  rN  rÉ   rô  rù  rý  r   r©   rÈ   r+  r  r  rä   r”  rÌ  Ú__classcell__©rá   s   @r_   rh   rh     s™  ø„ ñDð €Eð ð Ø"Ø"&ðàðð ðð ð	ð
  òó ðð  ð .2ØØ"Ø"&ðàðð +ðð ð	ð
 ðð  òó ðõ$/-ðf ò)ó ð)ð  ò|ó ð|ð| òDó ðDð
 òó ðð8 ò#ó ð#ð òó ðð òó ðð òó ðð òó ðð òó ðð òRó ðRð" ð -1ð.Tà&ð.Tð *ð.Tð 
ò	.Tó ð.Tð` ð —x‘xðàðð 
òó ðð ØCHÇ8Á8ó ó ðð& ð 7;Ø04ð	jà'ðjð 4ðjð .ð	jð
 
òjó ðjðX ð Ø7;ØØð4Yà&ð4Yð ð4Yð 5ð	4Yð
 ð4Yð ð4Yð 
ò4Yó ð4Yðl ØðØðØ!%ðà	òó ó ðð
 ØðØðØ!%ðà	òó ó ðð
 ò'ó ð'ðR ò$ó ð$ðL ð
 ×)Ñ)ð	(à$ð(ð "ð(ð
 
ò(ó ð(ðX ,4×+<Ñ+<ô $ðJ !ð2Bàð2Bð ð2Bð #ð	2Bð
 ð2Bð 
ó2Bóh;ó(1óLó

ô,ð2 >Bð	Øð	Ø ð	Ø):ð	à	ó	ó)ðV ó	ó ð	ð òó ðó"7+ór9óð09 Ø"ð9 Ø/9ð9 à	 ó9 ôvTó ó,!÷2ra   rh   c                  ó´   ‡ — e Zd ZdZdZ	 	 	 	 d		 	 	 	 	 	 	 d
ˆ fd„Zedd„«       Zedd„«       Z	eddd„«       Z
eej                  f	 	 	 	 	 dd„«       Zdd„Zˆ xZS )rj   a  A Shell is a fundamental component in build123d's topological data structure
    representing a connected set of faces forming a closed surface in 3D space. As
    part of a geometric model, it defines a watertight enclosure, commonly encountered
    in solid modeling. Shells group faces in a coherent manner, playing a crucial role
    in representing complex shapes with voids and surfaces. This hierarchical structure
    allows for efficient handling of surfaces within a model, supporting various
    operations and analyses.g      @c                óè  •— t        |t        «      rt        |«      n|}t        |t        «      rt        t        |«      x}«      dk(  r|d   }t        |t        «      rKt        t        |j                  «      j                  «       j                  «       «      }|j                  «       }n3t        |t        «      r#t        |D �cg c]  }|j                  ‘Œ c}«      }t        ‰| �1  ||||¬«       yc c}w )a_  Build a shell from an OCCT TopoDS_Shape/TopoDS_Shell

        Args:
            obj (TopoDS_Shape | Face | Iterable[Face], optional): OCCT Shell, Face or Faces.
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        r@   r   rÑ   N)rÓ   r   r  rÒ   rh   r   r
   rv   r›  rD   rI   rÙ   rÅ   )	r^   rl   rÂ   rÃ   rÄ   Úobj_listrÃ  r¡   rá   s	           €r_   rÅ   zShell.__init__œ  sÊ   ø€ ô & c¬8Ô4Œd�3Œi¸#ˆÜ�cœ8Ô$¬¼¸c»Ð-B¨XÓ)CÀqÒ)HØ˜1‘+ˆCä�cœ4Ô Ü.Ü# C§K¡KÓ0×8Ñ8Ó:×BÑBÓDóˆGð —-‘-“/‰CÜ˜œXÔ&Ü#¹Ó$<¹°1 Q§Y£Y¸Ñ$<Ó=ˆCä‰ÑØØØØð	 	õ 	
ùò %=s   ÃC/c                óà   — | j                   rbt        «       j                  | j                  «      }t	        «       }t
        j                  t        |«         } |||«       |j                  «       S y)z=volume - the volume of this Shell if manifold, otherwise zerorã   )	Úis_manifoldr!   ÚSolidFromShellrv   r   rD   Úshape_properties_LUTrJ   ÚMass)r^   Úsolid_shellrÏ  Úcalc_functions       r_   rU  zShell.volumeÀ  sZ   € ð ×ÒÜ(Ó*×9Ñ9¸$¿,¹,ÓGˆKÜ%›ˆJÜ!×6Ñ6´yÀÓ7MÑNˆMÙ˜+ zÔ2Ø—?‘?Ó$Ð$Øra   c                óf   — t        t        j                  t        |j                  |«      «      «      S )a/  extrude

        Extrude a Wire into a Shell.

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

        Raises:
            ValueError: Unsupported class
            RuntimeError: Generated invalid result

        Returns:
            Edge: extruded shape
        )rj   r*   r°  rM   rv   rr   s      r_   rt   zShell.extrudeÍ  s$   € ô  ”V—^‘^Ô$9¸#¿+¹+ÀyÓ$QÓRÓSÐSra   c                ó(   —  | t        |d|«      «      S )a
  make loft

        Makes a loft from a list of wires and vertices. Vertices can appear only at the
        beginning or end of the list, but cannot appear consecutively within the list nor
        between wires. Wires may be closed or opened.

        Args:
            objs (list[Vertex, Wire]): wire perimeters or vertices
            ruled (bool, optional): stepped or smooth. Defaults to False (smooth).

        Raises:
            ValueError: Too few wires

        Returns:
            Shell: Lofted object
        F)rO   )rk   ÚobjsÚruleds      r_   Ú	make_loftzShell.make_loftß  s   € ñ$ ”:˜d E¨5Ó1Ó2Ð2ra   c                óÒ  — t        |j                  «       «      }t        t        |j                  «       «      j                  «       «      }t        |j                  «      }|j                  |j                  dd«       |j                  t        j                  |   «       |j                  «        t        |j                  «       «      }t        j                  r|j                  «       }|S )aÂ  sweep

        Sweep a 1D profile along a 1D path

        Args:
            profile (Union[Curve, Edge, Wire]): the object to sweep
            path (Union[Curve, Edge, Wire]): the path to follow when sweeping
            transition (Transition, optional): handling of profile orientation at C1 path
                discontinuities. Defaults to Transition.TRANSFORMED.

        Returns:
            Shell: resulting Shell, may be non-planar
        F)rC   r»   Úorder_edgesr   rv   r…  r¼  rD   r½  r†  rj   rF   r¾  r¿  s         r_   rÄ  zShell.sweepó  s�   € ô( �w—}‘}“Ó'ˆÜ”D˜Ÿ™›Ó&×2Ñ2Ó4Ó5ˆÜ-¨d¯l©lÓ;ˆØ�‰�G—O‘O U¨EÔ2Ø×!Ñ!¤%×"6Ñ"6°zÑ"BÔCØ�‰ŒÜ�w—}‘}“Ó'ˆÜ�?Š?Ø—\‘\“^ˆFàˆra   c                óˆ   — t        «       }t        j                  | j                  |«       t	        |j                  «       «      S )zCenter of mass of the shell)r   r   ÚLinearProperties_srv   r=   rÉ  )r^   rÏ  s     r_   rü   zShell.center  s1   € ä!“^ˆ
Ü×$Ñ$ T§\¡\°:Ô>Ü�j×-Ñ-Ó/Ó0Ð0ra   r+  )rl   z+TopoDS_Shell | Face | Iterable[Face] | NonerÂ   r(  rÃ   r)  rÄ   r*  r-  )rl   rC   rs   r>   r°   rj   )F)rF  zIterable[Vertex | Wire]rG  r.  r°   rj   )rÀ  r0  rÁ  r0  r°   rj   r4  )r³   r´   rµ   r¶   r5  rÅ   r¾   rU  r¿   rt   rH  r6   r7  rÄ  rü   r8  r9  s   @r_   rj   rj   �  sÉ   ø„ ñ ð €Eð
 <@ØØ"Ø"&ð 
à8ð 
ð ð 
ð ð	 
ð
  õ 
ðH òó ðð òTó ðTð" ó3ó ð3ð& ð
 ×)Ñ)ð	à$ðð "ðð
 
òó ð÷B1ra   rj   c                óÜ   — t        | «      dk  r| gS t        | d   | dd «      }g }|j                  «       D ]3  }|j                  |j	                  «       g|j                  «       z   «       Œ5 |S )a%  Tries to determine how wires should be combined into faces.

    Assume:
        The wires make up one or more faces, which could have 'holes'
        Outer wires are listed ahead of inner wires
        there are no wires inside wires inside wires
        ( IE, islands -- we can deal with that later on )
        none of the wires are construction wires

    Compute:
        one or more sets of wires, with the outer wire listed first, and inner
        ones

    Returns, list of lists.

    Args:
      wire_list: list[Wire]:

    Returns:

    r[   r   r@   N)rÒ   rh   r„   r‘   rÈ   rÉ   )Ú	wire_listr„   r³  r€   s       r_   Úsort_wires_by_build_orderrO    s‚   € ô0 ˆ9ƒ~˜Òàð
ð 	
ô
 �˜1‘˜y¨¨˜}Ó-€Eà€LØ—‘–ˆØ×Ñà—‘Ó!ðð ×ÑÓ ñ!õ	
ð ð Ðra   )rN  r3  r°   zlist[list[Wire]])…r¶   Ú
__future__r   rx   r$  Útypingr   r   r   Úcollections.abcr   r   Ú
OCP.TopAbsÚTopAbsrc   ÚOCP.BRepr	   ÚOCP.BRepAdaptorr
   ÚOCP.BRepAlgor   ÚOCP.BRepAlgoAPIr   ÚOCP.BRepBuilderAPIr   r   ÚOCP.BRepClass3dr   ÚOCP.BRepFillr   ÚOCP.BRepFilletAPIr   ÚOCP.BRepGPropr   r   ÚOCP.BRepIntCurveSurfacer   ÚOCP.BRepOffsetAPIr   r   ÚOCP.BRepToolsr   r   Ú	OCP.GPropr   ÚOCP.Geomr   r   r   ÚOCP.GeomAPIr   r   ÚOCP.GeomAbsr   ÚOCP.Precisionr    ÚOCP.ShapeFixr!   ÚOCP.Standardr"   r#   r$   ÚOCP.StdFailr%   ÚOCP.TColStdr&   Ú
OCP.TColgpr'   Ú
OCP.TopExpr(   ÚOCP.TopToolsr)   Ú
OCP.TopoDSr*   r+   r,   r-   r.   ÚOCP.gcer/   ÚOCP.gpr0   r1   Úbuild123d.build_enumsr2   r3   r4   r5   r6   Úbuild123d.geometryr7   r8   r9   r:   r;   r<   r=   r>   Útyping_extensionsr?   Úone_drA   rB   rC   Ú
shape_corerD   rE   rF   rG   rH   rI   rJ   rK   rL   ÚutilsrM   rN   rO   rP   rQ   Úzero_drR   Úthree_drS   Ú	compositerT   rU   rV   rW   rY   rh   rj   rO  r\   ra   r_   Ú<module>ry     s  ðñ5õn #ã Û ß /Ñ /ç .å Ý Ý /Ý !Ý .ß PÝ 7Ý !Ý 8ß 3Ý =ß Tß 6Ý "ß UÑ Uß RÝ "Ý #Ý '÷ñ õ
 (Ý -Ý *Ý Ý Bß TÕ TÝ ß !ç NÕ N÷	÷ 	ó 	õ #ç &Ñ &÷
÷ 
õ 
÷õ õ ñ Ýß8Ó8ôx3ˆeô x3ôvI2ˆ7�E˜+Ñ&ô I2ôX$I1ˆG�U˜<Ñ(ô I1ôX)ra   