
    ^jY                   |   d Z ddlmZ ddlZddl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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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.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8 ddl9m:Z: ddl;m<Z< ddl=m>Z>m?Z? ddl@mAZA ddlBmCZC ddlDmEZE ddlFmGZG ddlHmIZImJZJ ddlKmLZL ddlMmNZN ddlOmPZPmQZQmRZRmSZS ddlTmUZUmVZVmWZW ddlXmYZYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z` ddlambZbmcZcmdZd dd lemfZf dd!lgmhZhmiZimjZjmkZkmlZlmmZmmnZnmoZompZp dd"lqmrZr dd#lsmtZtmuZumvZv dd$lwmxZx dd%lymzZzm{Z{m|Z| dd&l}m~Z~ dd'lmZmZmZmZmZmZmZmZmZmZmZmZmZ dd(lmZ dd)lmZ dd*lmZmZ dd+lmZ dd,lmZmZ dd-lmZ dd.lmZmZmZ dd/lmZmZmZmZ dd0lmZmZ dd1lmZmZ dd2lmZ dd3lmZmZmZmZmZmZmZ dd4lmZmZmZmZ dd5lmZ dd6lmZ dd7lmZmZ dd8lmZmZmZmZmZmZmZmZmZmZ dd9lmZmZmZmZmZmZmZmZmZmZ d:d;lmZmZmZmZmZmZmZ d:d<lmZmZmZmZmZmZmZmZmZ d:d=lmZmZmZ d:d>lmZmZ erd:d?lmZmZmZmZ d:d@lmZ d:dAlmZmZ  edBC       G dD dE             Z edBC       G dF dG             ZdZdIZ	 	 	 	 	 	 d[dJZ	 	 	 	 	 	 d\dKZd]dMZd^dNZ	 	 	 	 	 	 d[dOZ	 	 	 	 	 	 d_dPZ d`dQZ G dR dSee         Z G dT dLee         Z G dU dHee         ZdadbdVZdcdWZdej                  f	 	 	 	 	 	 	 dddXZ	 de	 	 	 	 	 dfdYZ	y)gas  
build123d topology

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

desc:

This module defines the classes and methods for one-dimensional geometric entities in the build123d
CAD library. It focuses on `Edge` and `Wire`, representing essential topological elements like
curves and connected sequences of curves within a 3D model. These entities are pivotal for
constructing complex shapes, boundaries, and paths in CAD applications.

Key Features:
- **Edge Class**:
  - Represents curves such as lines, arcs, splines, and circles.
  - Supports advanced operations like trimming, offsetting, splitting, and projecting onto shapes.
  - Includes methods for geometric queries like finding tangent angles, normals, and intersection
    points.

- **Wire Class**:
  - Represents a connected sequence of edges forming a continuous path.
  - Supports operations such as closure, projection, and edge manipulation.

- **Mixin1D**:
  - Shared functionality for both `Edge` and `Wire` classes, enabling splitting, extrusion, and
    1D-specific operations.

This module integrates deeply with OpenCascade, leveraging its robust geometric and topological
operations. It provides utility functions to create, manipulate, and query 1D geometric entities,
ensuring precise and efficient workflows in 3D modeling tasks.

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)bisect_right)IterableSequence)	dataclass)combinations)	atan2ceilcopysigncosfloorinfisclosepiradians)TYPE_CHECKING)cast)overload)BOPAlgo_Splitter)	BRep_Tool)BRepAdaptor_CompCurveBRepAdaptor_Curve)BRepAlgoAPI_CommonBRepAlgoAPI_Section)	BRepBuilderAPI_DisconnectedWireBRepBuilderAPI_EmptyWireBRepBuilderAPI_MakeEdgeBRepBuilderAPI_MakeFaceBRepBuilderAPI_MakePolygonBRepBuilderAPI_MakeVertexBRepBuilderAPI_MakeWireBRepBuilderAPI_NonManifoldWireBRepBuilderAPI_Transform)BRepExtrema_DistShapeShapeBRepExtrema_SupportType)BRepFilletAPI_MakeFillet2d)	BRepGProp)BRepLibBRepLib_FindSurface)	BRepLProp)BRepOffset_MakeOffset)BRepOffsetAPI_MakeOffset)BRepProj_Projection)	BRepToolsBRepTools_WireExplorer)ChFi2d_FilletAlgo)Extrema_ExtPC)GC_MakeArcOfCircleGC_MakeArcOfEllipseGC_MakeArcOfHyperbolaGC_MakeArcOfParabola)GCPnts_AbscissaPointGCPnts_QuasiUniformDeflectionGCPnts_UniformDeflection)Geom_BezierCurveGeom_BSplineCurveGeom_ConicalSurfaceGeom_CylindricalSurface	Geom_Line
Geom_PlaneGeom_SurfaceGeom_TrimmedCurve)Geom2d_CurveGeom2d_LineGeom2d_TrimmedCurve)Geom2dAPI_InterCurveCurve)	
GeomAbs_C0
GeomAbs_C1
GeomAbs_C2
GeomAbs_C3GeomAbs_Circle
GeomAbs_CN
GeomAbs_G1
GeomAbs_G2GeomAbs_JoinType)GeomAdaptor_Curve)GeomAPI_InterpolateGeomAPI_PointsToBSplineGeomAPI_ProjectPointOnCurve)#GeomConvert_CompCurveToBSplineCurve)GeomFill_CorrectedFrenetGeomFill_FrenetGeomFill_TrihedronLaw)GeomProjLib)gp_Ax1gp_Ax2gp_Ax3gp_Circgp_Dirgp_Dir2dgp_Elipsgp_Hyprgp_Parabgp_Pntgp_Pnt2dgp_Trsfgp_Vec)GProp_GProps)HLRAlgo_Projector)HLRBRep_AlgoHLRBRep_HLRToShape)ShapeAnalysis_FreeBounds)ShapeFix_ShapeShapeFix_Wireframe)Standard_ConstructionError)TColgp_Array1OfPntTColgp_Array1OfVecTColgp_HArray1OfPnt)TColStd_Array1OfIntegerTColStd_Array1OfRealTColStd_HArray1OfBooleanTColStd_HArray1OfReal)TopAbs_OrientationTopAbs_ShapeEnum)TopExpTopExp_Explorer)TopLoc_Location)TopoDSTopoDS_CompoundTopoDS_EdgeTopoDS_FaceTopoDS_ShapeTopoDS_VertexTopoDS_Wire)TopTools_HSequenceOfShape)TopTools_IndexedDataMapOfShapeListOfShapeTopTools_IndexedMapOfShapeTopTools_ListOfShape)minimize_scalar)
ConvexHull)Self
deprecated)
AngularDirectionCenterOfContinuityLevelFrameMethodGeomTypeKindPositionModeSagittaSideTangency)
DEG2RAD
TOL_DIGITS	TOLERANCEAxisColorLocationPlaneVector
VectorLikelogger   )_make_2tan_lines_make_2tan_on_arcs_make_2tan_rad_arcs_make_3tan_arcs_make_tan_cen_arcs_make_tan_on_rad_arcs_make_tan_oriented_lines)	TOPODSShape	ShapeList	SkipCleandowncastget_top_level_topods_shapes	shapetype
topods_dimunwrap_topods_compound)_extrude_topods_shape_make_topods_face_from_wires	isclose_b)Vertextopo_explore_common_vertex)CompoundCurvePartSketch)Solid)FaceShellT)frozenc                  D    e Zd ZU dZded<   ded<   ded<   ded<   d	ed
<   y)_WireFilletCornerz5Context needed to fillet a single planar wire corner.Wirewirer   vertexShapeList[Edge]	all_edgesconnected_edgesz	list[int]connected_edge_indicesN__name__
__module____qualname____doc____annotations__     Q/opt/ringagent/.cad-venv/lib/python3.12/site-packages/build123d/topology/one_d.pyr   r      s!    ?
JN$$%%r   r   c                  &    e Zd ZU dZded<   ded<   y)_WireFilletSolutionz-Replacement edges for a filleted wire corner.list[TopoDS_Edge]trimmed_topods_edgesrz   fillet_topods_edgeNr   r   r   r   r   r     s    7++##r   r   r   c                    | j                         }|j                  fd      }t              }|st        d|       t	        |      dk7  rt        d|       |D cg c]  }|j                  |       }}t        | |||      S c c}w )z;Collect the topology needed to fillet a single wire corner.c                H    t        fd| j                         D              S )Nc              3  h   K   | ])  }|j                   j                  j                          + y wN)wrappedIsSame).0edge_vertexr   s     r   	<genexpr>z@_analyze_wire_fillet_corner.<locals>.<lambda>.<locals>.<genexpr>  s.      
 &&v~~6
s   /2)anyvertices)edger   s    r   <lambda>z-_analyze_wire_fillet_corner.<locals>.<lambda>  s    S 
#}}
 
 r   z&Could not find shared vertex on wire:    z'Vertex must connect exactly two edges: )r   r   r   r   r   )edges	filter_bystr
ValueErrorlenindexr   )r   r   r   r   vertex_labeler   s    `     r   _analyze_wire_fillet_cornerr     s     

I))	
O v;LA,PQQ
?q B<.QRR:IJQiooa0JJ'5  Ks   !Bc                   t               }|j                  | j                  d   j                  | j                  d   j                  t        j
                  j                         t        j                  | j                  j                        }|j                  |      r|j                  |      dk(  ryt               t               }}|j                  |||      }t        ||g|      S )z>Try to fillet a planar wire corner with ``ChFi2d_FilletAlgo``.r   r   Nr   r   )r0   Initr   r   r   XYr   Pnt_sr   Perform	NbResultsrz   Resultr   )cornerradiusfillet_buildervertex_pointtrimmed_topods_edge0trimmed_topods_edge1r   s          r    _solve_wire_fillet_corner_chfi2dr   )  s    
 '(Nq!))q!)) ??6==#8#89L""6*##L1Q61<.'..*,@ 24HI- r   c                0   t        j                  |       }t        j                  |       }t        j                  |      }t        j                  |      j                  |      t        k  xs+ t        j                  |      j                  |      t        k  S )zCCheck whether an edge has the given vertex as one of its endpoints.)ru   FirstVertex_sLastVertex_sr   r   Distancer   )topods_edgetopods_vertexedge_vertex0edge_vertex1r   s        r   _topods_edge_contains_vertexr   G  su    
 ''4L&&{3L??=1L%..|<yH 	L??<(11,?)Kr   Edgec                   t               }|j                  | j                         |j                  |j                         |j	                          |j                         }g }t        |t        j                        }|j                         rS|j                  t        j                  |j                                      |j                          |j                         rS|S )zASplit an edge at a vertex and return the resulting edge segments.)r   AddArgumentr   AddToolr   r   rv   taTopAbs_EDGEMoreappendrx   r   CurrentNext)r   split_vertexsplittersplit_shapesplit_edgesexplorers         r   _split_edge_at_vertexr  U  s      !H&\))*.."KK{BNN;H
--/6;;x'7'7'9:; --/ r   c                   | j                   d   j                  | j                        }| j                   d   j                  | j                        }|j                  |      j                  t
        kD  ryt        d | j                   D              dz  }t        |gd | j                   D         }t        |t
        dz        }g }| j                   D ]  }t        j                  |j                        j                  | j                  j                        r!|j                  |t        j                        }n-|j                  |j                  |z
  t        j                        }|j                  t!        | j                        dz  t!        |      z
          t        | j                   d   j#                  |d         | j                   d   j#                  |d               t        t
        d	z  |d
z        k  S )zCDetermine if two incident edges are tangent-continuous at a corner.r   r   Fc              3  4   K   | ]  }|j                     y wr   lengthr   r   s     r   r   z<_wire_fillet_corner_is_tangent_continuous.<locals>.<genexpr>o  s     GGs   MbP?c              3  :   K   | ]  }|j                   d z    yw)      ?Nr  r  s     r   r   z<_wire_fillet_corner_is_tangent_continuous.<locals>.<genexpr>q  s     Ot+Os   d   r   
   r  )r   
tangent_atr   crossr  r   minmaxru   r   r   r   position_atr   LENGTHr  r   distance_to)r   tangent0tangent1sample_lengthreflected_pointsr   sample_points          r   )_wire_fillet_corner_is_tangent_continuousr%  g  s    %%a(33FMMBH%%a(33FMMBH~~h&&2G0F0FGG$NMO8N8NOM y37M&& R-44V]]5J5JK++M<;N;NOL++m+\-@-@L 	v}} 5 9F<<P PQR q!--.>q.ABq!--.>q.AB 
Y^]T1	23 3r   c                  
 t        | j                  |t        j                  t        d}|sy|j                  | j                        d   }g }| j                  D ]  }|j                         D cg c]  }|| j                  k7  s| c}d   
|j                         j                  |      d   }t        t        t        |      j                               j                               }t        t        j                  |      |      }	|j                  t!        
fd|	D                      t#        ||j$                        S c c}w )zIFallback fillet using the ``Geom2dGcc_Circ2d2TanRad`` tangent-arc solver.r   sagittaedge_factoryNr   c              3  N   K   | ]  }t        |j                        r|  y wr   )r   r   )r   r   other_vertexs     r   r   zD_solve_wire_fillet_corner_geom2dgcc_circ2d2tanrad.<locals>.<genexpr>  s)      /l6J6JK s   "%r   )r   r   r   BOTHr   sort_by_distancer   r   r   r    r   to_pntr  copydeepcopyr  nextr   r   )r   r   fillet_arcs
fillet_arcr   connected_edgevfillet_vertexr	  r  r+  s             @r   1_solve_wire_fillet_corner_geom2dgcc_circ2d2tanradr7    s-   
 &				K --fmm<Q?J 00 
#1#:#:#<SaV]]@RSTUV"++->>~NqQ%f]&;&B&B&DELLN
 ,DMM.,I<X## ' 	

 1%--  Ts   /EEc                D   | j                   D cg c]  }|j                   }}t        d      D ]e  }|j                  |   j	                         | j
                  |   j                  j	                         k7  sI|j                  |   j                          g t        d      D ]!  }|j                  |   || j                  |   <   # t        |      }| j                  d   | j                  d   dz   |z  k(  r| j                  d   dz   }n| j                  d   dz   }|j                  ||j                         t               }|D ]  }|j                  |        t               }	|	j                  |       |	j                          t!        |	j!                               S c c}w )z?Replace two connected edges with a fillet and rebuild the wire.r   r   r   )r   r   ranger   Orientationr   Reverser   r   insertr   r   Appendr!   AddBuildr   )
r   solutionr   all_topods_edgesininsert_indexcombined_edgesr   wire_builders
             r   _splice_wire_fillet_cornerrG    s   
 281A1ABBB 1X 7))!,88:%%a(00<<>? ))!,4467 1X 
))!, 	66q9:

 	A$$Q'F,I,I!,Lq,PTU+UU44Q7!;44Q7!;L(*E*EF)+N' +k*+*,L^$!!#$$= Cs   Fc                    t        | |      }t        |      r| S t        |      }t        ||      }|t	        ||      }|t        d| d|       t        ||      S )zHFillet a single planar wire corner with the available 2D fillet solvers.zFillet algorithm failed for z with radius )r   r%  r   r   r7  r   rG  )r   r   r   r   r   r@  s         r   _fillet_wire_cornerrI    sv     )v6F08v;L/?HDVVT*<.fXN
 	
 &fh77r   c                     e Zd ZdZed)d       Zed*d       Zed*d       Zed*d       Zed+d       Z	ed+d       Z
ed+d       Zed,d	       Ze	 	 	 	 	 	 d-d
       Zed.d       Zed/d       Zed0d       Zd Zd1dZd1dZd2dZej.                  fd3dZed	 	 	 	 	 d4dZ	 d5	 	 	 	 	 d6dZdej:                  f	 	 	 	 	 	 	 d7dZd8dZ	 	 d9	 	 	 	 	 	 	 d:dZ ej:                  e!jD                  df	 	 	 	 	 	 	 	 	 d;dZ#ej:                  e!jD                  df	 	 	 	 	 	 	 	 	 d<dZ$d8dZ%e&jN                  e(jR                  df	 	 	 	 	 	 	 	 	 d=dZ*e+jX                  f	 	 	 	 	 	 	 d>d Z-ej:                  f	 	 	 	 	 d?d!Z.dej:                  df	 	 	 	 	 	 	 d@d"Z/	 dA	 	 	 	 	 	 	 dBd#Z0	 	 	 dC	 	 	 	 	 	 	 	 	 dDd$Z1d8d%Z2d&ej:                  e+jX                  f	 	 	 	 	 	 	 dEd'Z3d&ej:                  f	 	 	 	 	 dFd(Z4y)GMixin1Dz+Methods to add to the Edge and Wire classesc                     y)zDimension of Edges and Wiresr   r   selfs    r   _dimzMixin1D._dim  s     r   c                n    | j                   t        d      t        j                  | j                        S )z#Are the start and end points equal?z/Can't determine if empty Edge or Wire is closed)_wrappedr   r   
IsClosed_sr   rM  s    r   	is_closedzMixin1D.is_closed  s/     == NOO##DLL11r   c                    | j                   t        d      | j                  j                         t        j
                  k(  S )z*Does the Edge/Wire loop forward or reversez/Can't determine direction of empty Edge or Wire)rQ  r   r   r:  rs   TopAbs_FORWARDrM  s    r   
is_forwardzMixin1D.is_forward  s9     == NOO||'')-?-N-NNNr   c                *   t        |       }|D cg c]  }t        || j                  dz         }}t        |d   |d   d      }|j	                          |j                         }t        |t        j                        }|j                         S c c}w )a1  
        Check if the edge is an interior edge.

        An interior edge lies between surfaces that are part of the body (internal
        to the geometry) and does not form part of the exterior boundary.

        Returns:
            bool: True if the edge is an interior edge, False otherwise.
        r  r   r   F)
PerformNow)
topo_explore_connected_facesoffset_topods_facer  r   r?  r   rv   r  r  r  )rN  topods_face_pairfoffset_face_pair	sectionorface_intersection_resultr  s          r   is_interiorzMixin1D.is_interior  s     8=>N
9:q$++"34
 

 (Q!1!!4
	 	#,??#4  ##;R^^L}}
s    Bc                v    t               }t        j                  | j                  |       |j	                         S )zEdge or Wire length)rd   r'   LinearProperties_sr   Mass)rN  propss     r   r  zMixin1D.length  s+     $$T\\59zz|r   c                
   | j                         }t        |t              r$| j                         j                  j
                  S |j                         t        k7  rt        d      |j                         j                         S )a  Calculate the radius.

        Note that when applied to a Wire, the radius is simply the radius of the first edge.

        Args:

        Returns:
          radius

        Raises:
          ValueError: if kernel can not reduce the shape to a circular edge

        z&Shape could not be reduced to a circle)geom_adaptor
isinstancer   r   firstr   GetTyperI   r   CircleRadius)rN  geoms     r   r   zMixin1D.radius  sd       "d12::<%%,,,<<>^+EFF{{}##%%r   c                     y)z>volume - the volume of this Edge or Wire, which is always zero        r   rM  s    r   volumezMixin1D.volume4  s     r   c                    t         j                  t        t         j                  t        t         j
                  t        i}t        |      } ||   t        |            S )z6Returns the right type of wrapper, given a OCCT object)	r  TopAbs_VERTEXr   r  r   TopAbs_WIREr   r   r   )clsobjconstructor_lut
shape_types       r   r   zMixin1D.cast;  sI     fNNDNND
 s^
*z*8C=99r   c                    t         S )z9Unused - only here because Mixin1D is a subclass of Shape)NotImplementedrs  rt  	directions      r   extrudezMixin1D.extrudeJ  s
    
 r   c                    t        |t        t        f      rt        |      S 	 t        |      }| j                  |      S # t        $ r}t	        | d|      |d}~ww xY w)z5Convert a float or VectorLike into a curve parameter.z$ must be a float or VectorLike, not N)rg  intfloatr   	TypeErrorparam_at_point)	edge_wirevaluenamepointexcs        r   	_to_paramzMixin1D._to_paramS  sn     ec5\*<	5ME
 ''..	  	&<UIF	s   ? 	AAAc                     y r   r   rN  others     r   __add__zMixin1D.__add__b  s    ,/r   c                     y r   r   r  s     r   r  zMixin1D.__add__d  s    NQr   c                   |g }nBt        |t              r|gn|D cg c]"  }t        |r|j                  nd      D ]  }| $ }}}|s| S t	        d |D              st        d      t        |D cg c],  }t        t        t        z  t        j                  |            . c}      }|D cg c]  }|j                         D ]  }|  }	}}| j                  !t        |      dk(  r|d   }
n3	 t        |	      }
n&	 t        | j                         t        |	      z         }
t&        j(                  r|
j)                         }
t        |
j                               dk(  r|
j+                         }
|
S |
}
|
S c c}}w c c}w c c}}w # t
        t        t         f$ r  |j"                  j$                  |dd  }
Y w xY w# t
        t        t         f$ r  | j$                  | }
Y w xY w)z"fuse shape to wire/edge operator +Nc              3  8   K   | ]  }t        |      d k(    yw)r   N)r   )r   summands     r   r   z"Mixin1D.__add__.<locals>.<genexpr>w  s     K:g&!+Ks   z0Only shapes with the same dimension can be addedr   r   )rg  r   r   r   allr   r   tcastr   r   rK  r   r   rQ  r   RuntimeErrorrk   rh  fuser   cleanr   )rN  r  topods_summandsoshapessummandsr  r   summand_edges	sum_shapes              r   r  zMixin1D.__add__f  s    = O
 &0u%=5'5 8aTR	  O  KK?KKOPP :IJQU4$;Q0J
 +3LwGMMOLqLLL== 8}!19!	C $] 3I
1 	-0H!HI	 ??!)I ),IOO,=(>!(CINN$	 JS	Q KL #L2LM C 3 3 3Xab\ BIC .HI 1%DIIx0	1s5   'E521E;/F 1F >%F< 0F98F9<#G"!G"c                $    | j                  |      S )zPosition on wire operator @)r  rN  positions     r   
__matmul__zMixin1D.__matmul__      ))r   c                $    | j                  |      S )zTangent on wire operator %)r  r  s     r   __mod__zMixin1D.__mod__  s    x((r   c                $    | j                  |      S )zLocation on wire operator ^location_atr  s     r   __xor__zMixin1D.__xor__  r  r   c                l   | j                   t        d      |t        j                  k(  r| j	                  d      }|S |t        j
                  k(  rEt               }t        j                  | j                  |       t        |j                               }|S | j                         j                         }|S )zCenter of object

        Return the center based on center_of

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

        Returns:
            Vector: center
        z$Can't find center of empty edge/wire      ?)rQ  r   r   GEOMETRYr  MASSrd   r'   rb  r   r   CentreOfMassbounding_boxcenter)rN  	center_ofmiddle
propertiess       r   r  zMixin1D.center  s     == CDD)))%%c*F  (--'%J((zBJ3356F  &&(//1Fr   )	tolerancec                  g }| g|D cg c]  }||	 }}t        d |D              rt        d      d}|D cg c]  }|j                         D ]  }|  }	}}t        d |	D              r~|	D cg c]  }t	        |dz  |dz         }
}t        d t        |
d      D              rC|
d   j                  }|
d   j                  }t        |
d         j                  }t        ||      }|t        t        d	 |            }t        d
 |      }|D cg c]  }|j                  dd       }}||z   }|D ]`  }|j                  t        j                  k(  rdnd}|j!                  t#        |      D cg c]  }|j%                  ||dz
  z         c}       b t        t'        |            }i }t        |d      D ];  }|d   |d   z
  }|d   |d   z
  }d|j)                  |      j*                  z  }|||<   = |t-        t        |j/                                     d      }|d   |d   z
  j1                         }|d   |d   z
  j)                  |      }	 t        t3        |t5        ddd            dz  |      t        fd|D              }|rnd}||S t3        |D cg c]  }|j%                  d       c}t5        ddd            t7        |      z  }t	        ||j8                        }|j;                  |      }t=        |t4              sJ |j?                  |      S c c}w c c}}w c c}w c c}w c c}w # t        $ r d}Y w xY wc c}w )a  common_plane

        Find the plane containing all the edges/wires (including self). If there
        is no common plane return None. If the edges are coaxial, select one
        of the infinite number of valid planes.

        Args:
            lines (sequence of Edge | Wire): edges in common with self
            tolerance (float): amount lines can deviate from plane. Defaults to TOLERANCE.

        Returns:
            None |  Plane: Either the common plane or None
        Nc              3  J   K   | ]  }t        |t        t        f         y wr   )rg  r   r   )r   lines     r   r   z'Mixin1D.common_plane.<locals>.<genexpr>  s     Hd:dT4L11Hs   !#zOnly Edges or Wires are validc              3  V   K   | ]!  }|j                   t        j                  k(   # y wr   )	geom_typer   LINEr   r   s     r   r   z'Mixin1D.common_plane.<locals>.<genexpr>  s     ?q{{hmm+?s   ')r   c              3  D   K   | ]  \  }}|j                  |        y wr   )
is_coaxial)r   a0a1s      r   r   z'Mixin1D.common_plane.<locals>.<genexpr>  s     LR2==$Ls    r   )z_dirc                     | j                   dk  S Ngd~QJr  r  s    r   r   z&Mixin1D.common_plane.<locals>.<lambda>  s    DKK44G r   c                     | j                   dkD  S r  r  r  s    r   r   z&Mixin1D.common_plane.<locals>.<lambda>  s    t1C r   r  r     r      )originr  c              3  B   K   | ]  }j                  |        y wr   )contains)r   pc_planer  s     r   r   z'Mixin1D.common_plane.<locals>.<genexpr>  s     LW--a;Ls   start) r   r   r   r  r   r   r  rz  r   x_dirlistfiltertrim_to_lengthr  r   r  extendr9  r  setr  r  sortedkeys
normalizedsumr   r   r  	intersectrg  shift_origin)rN  r  linespointsr  	all_linesresultlr   r   as_axisr  r  r  normal_linesinfinite_linesshortened_lines
num_pointsrB  extreme_areassubsetvector1vector2areaextremescommonglobal_centercenter_axisplane_originr  s    `                           @r   common_planezMixin1D.common_plane  sl   &  ""^U^(
t/?D(
	 (
 HiHH<==,5 Iqqwwy I! I I	 I?Y??3<=atAE1q5)=G=L<3KLL ,,
,,gaj)//vU3>'G STL#$CYONBPQQq//R8QOQ$6I! "&..HMM"AQq
EJ:EVWT%%a:>&:;W
 #f+&FM&vq1 - )fQi/ )fQi/gmmG4;;<&,d#	- %VD1C1C1E,F%G%KLH a[8A;.::<Ea[8A;.55e<E
5&Aq/:Q>u LVLL$*>M )23AQ]]336!Q?
	N =&,,7''4,///""<00E(
 !J= R X&   4s9   L)L)L.5L4L97L>
%M 'MMMNc           	     D   | j                   t        d      | j                         }|/t        t	        |j
                  j                        dt              st        d      t        j                  dd|| j                         }g }g g }}|D ]  }| j                  |d      }	| j                  |d      }
|j                  |	       |j                  |
       |	j                  |
      }|j                  |	j                  d	z  t        z   z  }|j                  dk\  rdnd
}|j                  ||z          t        t        t        d |D                    }t        | j!                         j"                        }||n|dz  }||z  }t%        t&                  }t)        |||      D ]x  \  }}}	t	        ||z  x}      t        k  r| |z  }|	j+                         j                  t-        ddd            }|j                  t&        j/                  ||||z  z                z |S )u^  
        Build a *curvature comb* for a planar (XY) 1D curve.

        A curvature comb is a set of short line segments (“teeth”) erected
        perpendicular to the curve that visualize the signed curvature κ(u).
        Tooth length is proportional to |κ| and the direction encodes the sign
        (left normal for κ>0, right normal for κ<0). This is useful for inspecting
        fairness and continuity (C0/C1/C2) of edges and wires.

        Args:
            count (int, optional): Number of uniformly spaced samples over the normalized
                parameter. Increase for a denser comb. Defaults to 100.
            max_tooth_size (float | None, optional): Maximum tooth height in model units.
                If None, set to 10% maximum curve dimension. Defaults to None.

        Raises:
            ValueError: Empty curve.
            ValueError: If the curve is not planar on `Plane.XY`.

        Returns:
            ShapeList[Edge]: A list of short `Edge` objects (lines) anchored on the curve
            and oriented along the left normal `n̂ = normalize(t) × +Z`.

        Notes:
            - On circles, κ = 1/R so tooth length is constant.
            - On straight segments, κ = 0 so no teeth are drawn.
            - At inflection points κ→0 and the tooth flips direction.
            - At C0 corners the tangent is discontinuous; nearby teeth may jump.
              C1 yields continuous direction; C2 yields continuous magnitude as well.

        Example:
            >>> comb = my_wire.curvature_comb(count=200, max_tooth_size=2.0)
            >>> show(my_wire, Curve(comb))

        z+Can't create curvature_comb for empty curve      ?abs_tolz0curvature_comb only works for curves on Plane.XYr   r   )endpointr   r  g      c              3  2   K   | ]  }t        |        y wr   )abs)r   ks     r   r   z)Mixin1D.curvature_comb.<locals>.<genexpr>Q  s     +CqCF+C   r  )rQ  r   r  r   r  r  Zr   nplinspacerS  derivative_atr  r  r  r  r  sizer   r   zipr  r   	make_line)rN  countmax_tooth_sizeplnu_valueskappastangents
curvaturesutangent	curvaturer  kappasignmax_kappa_size
curve_sizescale
comb_edgesr  pnt_on_curve	kappa_dirs                        r   curvature_combzMixin1D.curvature_comb  s   L == JKK!;gc#))++&6YOOPP ;;q!U5GH !2* 		(A((A.G**1a0IOOG$i(MM),ELLGNNA$5	$ABE''Q,3DDMM$,'		( Y+CF+C(CD**,112
,8Nj2o 	 /t_&
!$Xvx!@ 		AugUU]*6+i7!8L**,226!Q?CI|\FY<N-NO		 r   r   c                b   t        |t        t        f      r| j                  ||      \  }}}nc	 t	        |      t        | t              rt        | j                         fd      }n| }|j                        }	|j                  |	      \  }}}|j                  ||      }
|
j                         dk(  rt	        ddd      S t	        |
      }|dz  dk(  r;t        | t              r|| j                  k(  }|r|}|S | }|S | j                  r|n| }|S # t
        $ r}t        d      |d}~ww xY w)a  Derivative At

        Generate a derivative along the underlying curve.

        Args:
            position (float | VectorLike): distance, parameter value or point
            order (int): derivative order. Defaults to 2
            position_mode (PositionMode, optional): position calculation mode. Defaults to
                PositionMode.PARAMETER.

        Raises:
            ValueError: position must be a float or a point

        Returns:
            Vector: position on the underlying curve
        z#position must be a float or a pointNc                &    | j                        S r   )r  )r   point_on_curves    r   r   z'Mixin1D.derivative_at.<locals>.<lambda>  s    !--:W r   keyr   r   r   )rg  r~  r}  _occt_param_atr   	Exceptionr   r   r  r   r  DN	MagnituderV  )rN  r  orderposition_mode
comp_curve
occt_paramclosest_forwardr  closestu_valuederivative_gp_vec
derivativeedge_same_as_wirer  s                @r   r  zMixin1D.derivative_atf  sD   , h-6:6I6I-73J
OQ!'!1 $%djjl0WX,,^<G6=6L6LW6U3J
O&MM*e<&&(A-!Q?"-.
19>$%$3t$F!+<Z
 	 DN+
  ,0??Z
-  Q !FGSPQs   D 	D.D))D.c                    | j                         }| j                  r|j                         n|j                         }t	        |j                  |            S )zhThe end point of this edge.

        Note that circles may have identical start and end points.
        )rf  rV  LastParameterFirstParameterr   Value)rN  curveumaxs      r   	end_pointzMixin1D.end_point  sE    
 !!#(,u""$U=Q=Q=Sekk$'((r   c                   t        |t              rt        |      }nAt        |t              rt        |j                        }nt        |t
              rt        |      }t               }t        |t              re|j                  rY| j                  d      }|j                  |j                  |j                         |j                         z
  j                  z         }t        |t              rjt        t!        |j"                        j%                               }| j'                  | f|ft)                     }|j+                  |j-                                nt        |t        t.        f      r| j'                  | f|ft1                     }|j+                  |j-                                | j'                  | f|ft)                     }|D ]1  }	t        |	t              s|	j2                  r!|j5                  |	       3 n\t        |t              r&|j7                  |       |k  r8|j5                  |       n&|j9                  | ||      }
|
r|j+                  |
       |r|S dS )u   Single-object intersection for Edge/Wire.

        Returns same-dimension overlap or crossing geometry:
        - 1D + 1D → Edge (collinear overlap) + Vertex (crossing)
        - 1D + Face/Solid/Compound → delegates to other._intersect(self)

        Args:
            other: Shape or geometry object to intersect with
            tolerance: tolerance for intersection detection
            include_touched: if True, include boundary contacts
                (only relevant when Solids are involved)
        F)optimalN)rg  r   r   r   r  r   r   r   is_infiniter  trim_infinitediagonalr  r  r   r   r   r   r   _bool_op_listr   r  expandr   r   is_nullr  r  
_intersect)rN  r  r  include_touchedresultsbboxfacesectionr  r  r  s              r   r1  zMixin1D._intersect  s   & eV$5MEx(5>>*Et$KE&[ eT"u'8'8$$U$3D''$++-!? G GGE
 eU# 7 F K K MND(($4';N;PQGNN7>>+, d|,''%;M;OPFNN6==?+(($5(<O<QRG  *eV,U]]NN5)*
 v&  &)3u% %%dIGFv&!w+t+r   c                   | j                         }| j                  s(|t        j                  k(  rd|z
  }n| j                  |z
  }t        | t              r|t        j                  k(  r| j                  || j                  z        }n|t        j                  k(  r2| j                  || j                  z  t        j                        \  }}}nx| j                  |t        j                        \  }}}nS|t        j                  k(  r| j                  |      }n| j                  || j                  z        }| j                         }|t        j                  k(  rt               }n
t               }|j                  |       t!               t!               t!               }}
}	|j#                  ||	|
|       |j%                  |      }t'               }|U	 |j)                  t+        |t-        |	j/                               t1        |      j3                               t+                      nS|j)                  t+        |t-        |	j/                               t-        |
j/                                     t+                      t;        t=        |            }| j                  r|S | S # t4        $ r*}t7        d| dt9        t1        |	             d      |d}~ww xY w)u  Locations along curve

        Generate a location along the underlying curve.

        Args:
            distance (float): distance or parameter value
            position_mode (PositionMode, optional): position calculation mode.
                Defaults to PositionMode.PARAMETER.
            frame_method (FrameMethod, optional): moving frame calculation method.
                The FRENET frame can “twist” or flip unexpectedly, especially near flat
                spots. The CORRECTED frame behaves more like a “camera dolly” or
                sweep profile would — it's smoother and more stable.
                Defaults to FrameMethod.FRENET.
            x_dir (VectorLike, optional): override the x_dir to help with plane
                creation along a 1D shape. Must be perpendicular to shapes tangent.
                Defaults to None.

        Returns:
            Location: A Location object representing local coordinate system
                at the specified distance.
        r   Nz+Unable to create location with given x_dir z1. x_dir must be perpendicular to shape's tangent .)rf  rV  r   	PARAMETERr  rg  r   r   	CORRECTEDparam_atr  r  FRENETrT   rS   SetCurverc   D0r%  rb   SetTransformationrY   r[   XYZr   to_dirrk   r   tupler   rw   )rN  distancer  frame_methodr  r&  param_lawr  normalbinormalpnttransformationr  locs                   r   r  zMixin1D.location_at  sU   8 !!# 6 66x<;;1dD!{444h&<= !L$:$::&*&9&9 4;;.0C0C'OE5! '+&9&9(LDWDW&XOE5!  6 66h/h&<=%%'E ;---!#C*,CU$*Hfhugvx0kk%  
003w{{} 5ve}7K7K7MNPVPX ,,sF7;;=16&**,3GH&( ~67??Jt .  A% IFVG_-.a1 	s   AJ 	K"%KKc           	     P    |D cg c]  }| j                  ||||       c}S c c}w )a  Locations along curve

        Generate location along the curve

        Args:
            distances (Iterable[float]): distance or parameter values
            position_mode (PositionMode, optional): position calculation mode.
                Defaults to PositionMode.PARAMETER.
            frame_method (FrameMethod, optional): moving frame calculation method.
                Defaults to FrameMethod.FRENET.
            x_dir (VectorLike, optional): override the x_dir to help with plane
                creation along a 1D shape. Must be perpendicular to shapes tangent.
                Defaults to None.

        Returns:
            list[Location]: A list of Location objects representing local coordinate
                systems at the specified distances.
        r  )rN  	distancesr  rD  r  ds         r   	locationszMixin1D.locationsB  s4    4 NW
HIDQ|UC
 	
 
s   #c                   | j                   t        d      | j                         }| j                  }|t        j
                  k(  r9|j                         }t        |j                         j                               }|S |t        j                  k(  r9|j                         }t        |j                         j                               }|S t        | j                  d      }|j                         }t        |t               r9|j#                         }t        |j                         j                               }|S t        d      )zCalculate the normal Vector. Only possible for planar curves.

        :return: normal vector

        Args:

        Returns:

        z$Can't find normal of empty edge/wireT)	OnlyPlanezNormal not defined)rQ  r   rf  r  r   CIRCLErj  r   r   	DirectionELLIPSEEllipser)   r   Surfacerg  r>   Pln)	rN  r&  gtypecircreturn_valueellfind_surfacesurfr  s	            r   rH  zMixin1D.normal_  s	    == CDD!!#HOO#<<>D!$))+"7"7"9:L  h&&&--/C!#((*"6"6"89L  /t||tLL'')D$
+hhj%chhj&:&:&<=  !!566r   Tc           	     |   t         j                  t        j                  t         j                  t        j
                  t         j                  t        j                  i}t        | t              r| nt        | g      }t        |j                               dk(  rM|j                         d   }|j                  dd      |j                  dd      g}t        |      j                  }	n|j                  }	|	J t               }
|
j                  ||          |
j!                  |	       |
j#                  |       t%        |
j'                               }t        |t(              rt+        |d      }t        |t,              rt        |      }nt/        d      |t0        j2                  k7  r|j5                  d      |j5                  d      f|j                         j7                  fd	d
      }t9        |      }|D cg c]  }|j5                  d       }}|D cg c]4  }|j;                  d      j=                  ||j5                  d      z
        6 }}|t0        j>                  k(  r|tA        |d   |d   kD           }n|tA        |d   |d   k           }|r|j5                  d      }|j5                  d      }|j5                  d      }|j5                  d      }||z
  jB                  tE        |      z
  tF        k  r-tH        jK                  ||      }tH        jK                  ||      }n,tH        jK                  ||      }tH        jK                  ||      }t        |j                         |j                         z   tM        ||g      z         }|j                         }t        |      dk(  r|d   S |S c c}w c c}w )aB  2d Offset

        Offsets a planar edge/wire

        Args:
            distance (float): distance from edge/wire to offset
            kind (Kind, optional): offset corner transition. Defaults to Kind.ARC.
            side (Side, optional): side to place offset. Defaults to Side.BOTH.
            closed (bool, optional): if Side!=BOTH, close the LEFT or RIGHT
                offset. Defaults to True.
        Raises:
            RuntimeError: Multiple Wires generated
            RuntimeError: Unexpected result type

        Returns:
            Wire: offset wire
        r   r   rn  r  r  T)fullyzUnexpected result typec                l      j                   t        j                  k(  xr t         fdD              S )Nc              3  ^   K   | ]$  }j                   |z
  j                  t        k   & y wr   )
arc_centerr  r   )r   ptr   s     r   r   z6Mixin1D.offset_2d.<locals>.<lambda>.<locals>.<genexpr>  s%     WrQ\\B.66BWs   *-)r  r   rS  r   )r   	endpointss   `r   r   z#Mixin1D.offset_2d.<locals>.<lambda>  s,    KK8??2 XWYWW r   )reverse)'r   ARCrM   GeomAbs_ArcINTERSECTIONGeomAbs_IntersectionTANGENTGeomAbs_Tangentrg  r   r   r   trimr   r,   r   AddWirer   r   r   ry   r   r~   r  r   r,  r  r   edges_to_wiresr  get_signed_angleLEFTr}  r  r  r   r   r  r   )rN  rC  kindsideclosed	kind_dictr  r   r   topods_wireoffset_builderrt  offset_wireoffset_edgeswireswcenterscanglesself0self1end0end1edge0edge1re  s                            @r   	offset_2dzMixin1D.offset_2d  sC   4 HH&22/DDLL*::
	
 "$-t4< tzz|!::<?DYYsC($))C*=>Eu+--K,,K&&&13IdO,{+x(~++-.c?+(D9Cc;'s)K788499))!,d.>.>q.ABI&,,.88  9 L #<0E389aq}}S)9G9 ! "33A8H8H8K4KLF  tyy #Cq	F1I(=$>?#Cq	VAY(>$?@((+((+"..q1"..q1DL((3x=8IE NN5$7E NN5$7E NN5$7E NN5$7E"JJL;#4#4#66E5>9RR #((*"%l"3q"8|AIkI5 :s   ;N49N9c                    | j                  |      }t        || j                  |      |j                        }t        j                  ||j                  |z  dz  z   ||j                  |z  dz  z
        }|S )a  perpendicular_line

        Create a line on the given plane perpendicular to and centered on beginning of self

        Args:
            length (float): line length
            u_value (float): position along line between 0.0 and 1.0
            plane (Plane, optional): plane containing perpendicular line. Defaults to Plane.XY.

        Returns:
            Edge: perpendicular line
        )r  r  r  r   )r  r   r  r  r   r  y_dir)rN  r  r  planer  local_planer  s          r   perpendicular_linezMixin1D.perpendicular_line  sy       ) 8
 ~~K%%.22K%%.22
 r   c                b    | j                  ||      \  }}}t        |j                  |            S )a_  Position At

        Generate a position along the underlying Wire.

        Args:
            position (float): distance or parameter value
            position_mode (PositionMode, optional): position calculation mode. Defaults to
                PositionMode.PARAMETER.

        Returns:
            Vector: position on the underlying curve
        )r  r   r%  )rN  r  r  edge_curve_adaptorocct_edge_paramrF  s         r   r  zMixin1D.position_at  s:      261D1Dm2
.OQ (..?@@r   c                ^   || j                         }|j                         t        t        t        fv rt               }n
t               }|j                  |||j                         |j                                |j                         r|j                         dk(  rt        d      t        |j                               D cg c].  }t        |j                  |j!                  |dz                     0 c}S | |D cg c]  }| j#                  ||       c}S t%        d      c c}w c c}w )au  Positions along curve

        Generate positions along the underlying curve

        Args:
            distances (Iterable[float] | None, optional): distance or parameter values.
                Defaults to None.
            position_mode (PositionMode, optional): position calculation mode only applies
                when using distances. Defaults to PositionMode.PARAMETER.
            deflection (float | None, optional): maximum deflection between the curve and
                the polygon that results from the computed points. Defaults to None.


        Returns:
            list[Vector]: positions along curve
        r   zDeflection calculation failedr   z/Either distances or deflection must be provided)rf  
ContinuityrG   rH   rJ   r8   r7   
Initializer$  r#  IsDoneNbPointsr  r9  r   r%  	Parameterr  r   )rN  rN  r  
deflectionr&  discretizerrB  rO  s           r   	positionszMixin1D.positions  s"   , !?C?P?P?RE!j*j%II -.  <=""$$&##%	 %%';+?+?+AQ+F"#BCC {3356 u{{;#8#8Q#?@A   @IJ1D$$Q6JJJKK
 Ks   3D%>D*c                   | j                   |st        d      t        | j                  |j                  t	        |      j                               }|j                         }|rt               }|j                  | j                         t        }t        |      D ]P  }|j                  |       |j                          |j                         }	|	|k  s:|	}t        j                  |      }
R 
S t!        d t        |      D              }
|
S )zProject onto a face along the specified direction

        Args:
          face: Face:
          direction: VectorLike:
          closest: bool:  (Default value = True)

        Returns:

        z3Can't project an empty Edge or Wire onto empty Facec              3  F   K   | ]  }t         j                  |        y wr   )rK  r   )r   r  s     r   r   z"Mixin1D.project.<locals>.<genexpr>h  s      %(-U#%s   !)rQ  r   r-   r   r   rA  r   r$   LoadS1r   r   LoadS2r   r%  rK  r   r   )rN  r5  rz  r  bldrshapes	dist_calcmin_distr  distr[  s              r   projectzMixin1D.project?  s     == RSS"LL$,,y(9(@(@(B
 #'**,
 24IT\\*H 5V< 7  '!!# ((?#H#*<<#6L7 	 % %1LV1T% L r   c                   d }| j                   t        d      t               }|j                  | j                         t        |      }|rt        |      n| j                         }||z
  j                         }t        |      j                         }t               }|j                  t        |j                         |j                                      |j                  |j                                |rt        ||      n
t        |      }	|j                  |	       |j!                          |j#                          t%        |      }
g }|
j'                         |
j)                         |
j+                         fD ]3  }|j-                         r|j/                   |t1        |                   5 g }|
j3                         |
j5                         |
j7                         fD ]3  }|j-                         r|j/                   |t1        |                   5 |D ]  }t9        j:                  |t<                |D ]  }t9        j:                  |t<                t?        d |D              }t?        d |D              }||fS )a  project_to_viewport

        Project a shape onto a viewport returning visible and hidden Edges.

        Args:
            viewport_origin (VectorLike): location of viewport
            viewport_up (VectorLike, optional): direction of the viewport y axis.
                Defaults to (0, 0, 1).
            look_at (VectorLike, optional): point to look at.
                Defaults to None (center of shape).
            focus (float, optional): the focal length for perspective projection
                Defaults to None (orthographic projection)

        Returns:
            tuple[ShapeList[Edge],ShapeList[Edge]]: visible & hidden Edges
        c                    g }t        | t        j                        }|j                         rKt	        |j                               }|j                  |       |j                          |j                         rK|S r   )rv   rt   r  r  r   r  r  r  )compoundr   r  r   s       r   extract_edgesz2Mixin1D.project_to_viewport.<locals>.extract_edges  sa    E 'x1A1M1MNH --/ 0 0 23T" --/
 Lr   zCan't project empty edge/wirec              3  2   K   | ]  }t        |        y wr   r   r  s     r   r   z.Mixin1D.project_to_viewport.<locals>.<genexpr>  s     !Aa$q'!Ar  c              3  2   K   | ]  }t        |        y wr   r  r  s     r   r   z.Mixin1D.project_to_viewport.<locals>.<genexpr>  s      ?Qa ?r  ) rQ  r   rf   r>  r   r   r  r  rX   SetAxisrW   r.  rA  SetYDirectionre   	ProjectorUpdateHiderg   	VCompoundRg1LineVCompoundOutLineVCompoundIsNullr  r   	HCompoundOutLineHCompoundRg1LineHCompoundr(   BuildCurves3d_sr   r   )rN  viewport_originviewport_uplook_atfocusr  hidden_line_removalprojection_dircamera_coordinate_system	projector
hlr_shapesvisible_edgesr   hidden_edgesr   s                  r   project_to_viewportzMixin1D.project_to_viewportn  sI   0	 == <== +n- 1%,&/$++-"1G";!G!G!I[)446#)8  ((?))+^-B-B-DE	
 	!..{/A/A/CD  6>"#;< 	 	%%i0""$  "'(;<
   "'')'')
 	EE
 <<>$$]8E?%CD	E   "'')'')
 	DE
 <<>##M(5/$BC	D " 	5D##D)4	5  	5D##D)4	5 "!A=!AA  ?, ??|,,r   c                    | j                         }| j                  r|j                         n|j                         }t	        |j                  |            S )ziThe start point of this edge

        Note that circles may have identical start and end points.
        )rf  rV  r$  r#  r   r%  )rN  r&  umins      r   start_pointzMixin1D.start_point  sE    
 !!#)-u##%e>Q>Q>Sekk$'((r   r  c                    | j                  ||      }|j                  j                  ||j                        dz   dz  }|S )a  tangent_angle_at

        Compute the tangent angle at the specified location

        Args:
            location_param (float, optional): distance or parameter value. Defaults to 0.5.
            position_mode (PositionMode, optional): position calculation mode.
                Defaults to PositionMode.PARAMETER.
            plane (Plane, optional): plane line was constructed on. Defaults to Plane.XY.

        Returns:
            float: angle in degrees between 0 and 360
        h       v@)r  r  rp  r  )rN  location_paramr  r  
tan_vectorangles         r   tangent_angle_atzMixin1D.tangent_angle_at  s>    & __^]C
--j%++FLPUUr   c                D    | j                  |d|      j                         S )a  tangent_at

        Find the tangent at a given position on the 1D shape where the position
        is either a float (or int) parameter or a point that lies on the shape.

        Args:
            position (float |  VectorLike): distance, parameter value, or
                point on shape. Defaults to 0.5.
            position_mode (PositionMode, optional): position calculation mode.
                Defaults to PositionMode.PARAMETER.

        Returns:
            Vector: tangent value
        r   )r  r  )rN  r  r  s      r   r  zMixin1D.tangent_at  s"    & !!(A}=HHJJr   )returnr}  r  bool)r  r~  )rt  r|   r  zVertex | Edge | Wire)rt  r   rz  r   r  z&Edge | Face | Shell | Solid | Compound)r  rK  r  float | VectorLiker  r   r  r~  )r  Noner  r   )r  zShape | Iterable[Shape]r  zEdge | Wire | Curve)r  r~  r  r   )r  r~  r  r   )r  r   r  r   )r  zEdge | Wire | Noner  r~  r  zNone | Plane)r  N)r  r}  r  float | Noner  r   )r  r  r  r}  r  r   r  r   r  r   )ư>F)r  z(Shape | Vector | Location | Axis | Planer  r~  r2  r  r  zShapeList | None)
rC  r~  r  r   rD  r   r  VectorLike | Noner  r   )
rN  Iterable[float]r  r   rD  r   r  r  r  list[Location])
rC  r~  rr  r   rs  r   rt  r  r  Edge | Wire)r  r~  r  r~  r  r   r  r   )r  r~  r  r   r  r   )rN  Iterable[float] | Noner  r   r  r  r  zlist[Vector]T)r5  r   rz  r   r  r  r  z$Edge | Wire | ShapeList[Edge | Wire])r   r   r   NN)
r  r   r  r   r  r  r  r  r  z'tuple[ShapeList[Edge], ShapeList[Edge]])r  r~  r  r   r  r   r  r~  )r  r  r  r   r  r   )5r   r   r   r   propertyrO  rS  rV  r`  r  r   ro  classmethodr   r{  staticmethodr  r   r  r  r  r  r   r  r  r   r  r  r   r9  r  r(  r1  r   r<  r  rP  rH  r   rg  r   r,  r  r   r   r  r  r  r  r  r  r  r  r   r   r   rK  rK    sr   5   2 2 O O  6   & &,   : : $.	/  
/ 
/ / /Q Q/b*)* ,4+<+< 2 >GV1(V15:V1	V1r @DQQ0<Q	Ql &2&<&<	3$3 3 $	3
 
3j)   %	>,7>, >, 	>,
 
>,F '3&<&<$/$6$6#'[[ $[ "	[
 ![ 
[@ '3&<&<$/$6$6#'
"
 $
 "	

 !
 

: J XXYY]J]J ]J 	]J
 ]J 
]J@ =BHH&+49	4 >J=S=SAA.:A	A0 -1&2&<&<#'	.L).L $.L !	.L
 
.Lb BF--%/-:>-	--d #,%)"`-#`-  `- #	`-
 `- 
1`-D) !$&2&<&<xx	 $ 	
 
2 (+&2&<&<K$K $K 
	Kr   rK  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>d       Z
eej                  d	d
ej                  f	 	 	 	 	 	 	 	 	 	 	 d?d       Zeeej$                  d	 	 	 	 	 	 	 	 	 d@d              Zeeej$                  d	 	 	 	 	 	 	 	 	 dAd              Zeeej$                  d	 	 	 	 	 	 	 	 	 dBd              Zee	 	 	 	 	 	 dCd              Zee	 	 	 	 	 	 	 	 dDd              Zeej$                  d	 	 	 dEd       Zee	 	 	 	 	 	 dFd              Zee	 	 	 	 	 	 dGd              Zeeddd	 	 	 	 	 	 	 	 	 dHd              ZedId       Zeej                  d	d	ej                  f	 	 	 	 	 	 	 	 	 	 	 	 	 dJd       Zeej                  ddej                  f	 	 	 	 	 	 	 	 	 	 	 dKd       Zeej                  d	d	ej                  f	 	 	 	 	 	 	 	 	 	 	 	 	 dJd       Ze	 	 	 	 dL	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dMd       ZedNd       ZedOdPd       Ze	 	 	 	 	 dQ	 	 	 	 	 	 	 	 	 	 	 	 	 dRd        Ze	 	 dS	 	 	 	 	 	 	 	 	 	 	 dTd!       Ze	 	 	 	 dU	 	 	 	 	 	 	 	 	 	 	 dVd"       Ze	 	 	 	 	 	 	 	 dWd#       Ze	 	 	 	 	 	 	 	 dXd$       ZdYd%Z 	 	 	 dZ	 	 	 	 	 	 	 	 	 	 	 d[d&Z!	 d\	 	 	 	 	 d]d'Z"de#f	 	 	 	 	 d^d(Z$	 	 	 	 d_d)Z%d`d*Z&	 	 da	 	 	 	 	 	 	 dbd+Z'e(jR                  f	 	 	 	 	 dcd,Z*ddd-Z+ded.Z,	 	 df	 	 	 	 	 	 	 dgd/Z-dhdid0Z. e/d1      djd2       Z0 e/d3      dkd4       Z1dld5Z2dmd6Z3	 	 	 	 	 	 dnd7Z4edod8       Z5dpd9Z6 xZ7S )qr   a  An Edge in build123d is a fundamental element in the topological data structure
    representing a one-dimensional geometric entity within a 3D model. It encapsulates
    information about a curve, which could be a line, arc, or other parametrically
    defined shape. Edge is crucial in for precise modeling and manipulation of curves,
    facilitating operations like filleting, chamfering, and Boolean operations. It
    serves as a building block for constructing complex structures, such as wires
    and faces.r  Nc                    t        |t              rSt        t        |j                  j                         |j                  j                                     j                         }t        | )  ||||       y)aD  Build an Edge from an OCCT TopoDS_Shape/TopoDS_Edge

        Args:
            obj (TopoDS_Edge | Axis, optional): OCCT Edge or Axis.
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        rt  labelcolorparentN)rg  r   r   r=   r  r.  rz  rA  r   super__init__)rN  rt  r  r  r  	__class__s        r   r  zEdge.__init__  sm      c4 )LL'')MM((*
 df  		 	 	
r   c                ~   | j                   }| j                         }|t        j                  k(  r7t	        |j                         j                         j                               }|S |t        j                  k(  r7t	        |j                         j                         j                               }|S t        | d      )z3center of an underlying circle or ellipse geometry.z has no arc center)r  rf  r   rS  r   rj  Positionr   rU  rV  r   )rN  r  rf  r[  s       r   rc  zEdge.arc_center6  s     NN	((*'!,"5"5"7"@"@"B"K"K"MNL  (***!,"6"6"8"A"A"C"L"L"NOL  	{*<=>>r   c                    |st        d      t        t        j                  t        |j                  |                  S )a1  extrude

        Extrude a Vertex into an Edge.

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

        Raises:
            ValueError: Unsupported class
            RuntimeError: Generated invalid result

        Returns:
            Edge: extruded shape
        zCan't extrude empty vertex)r   r   rx   r   r   ry  s      r   r{  zEdge.extrudeH  s3      9::FKK 5ckk9 MNOOr   )weightsc               |   t        |      dk  rt        d      t        |      dkD  rt        d      |r"t        |      t        |      k7  rt        d      |D cg c]  }t        |      j                          }}t	        dt        |            }t        |      D ]  \  }}|j                  |dz   |        |rSt        dt        |            }t        |      D ]#  \  }}	|j                  |dz   t        |	             % t        ||      }
nt        |      }
 | t        |
      j                               S c c}w )a  make_bezier

        Create a rational (with weights) or non-rational bezier curve.  The first and last
        control points represent the start and end of the curve respectively.  If weights
        are provided, there must be one provided for each control point.

        Args:
            cntl_pnts (sequence[VectorLike]): points defining the curve
            weights (list[float], optional): control point weights list. Defaults to None.

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

        Returns:
            Edge: bezier curve
        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   r   r   r.  rl   	enumerateSetValuerp   r~  r9   r   r   )rs  r  	cntl_pntscntl_pntcntl_gp_pntspolesrB  cntl_gp_pntpole_weightsweightbezier_curves              r   make_bezierzEdge.make_bezier\  s2   , y>AK  y>BIJJ9~W- !STTBKLhx(//1LL #1c,&78'5 	/NA{NN1q5+.	/ /3w<@L&w/ <	6%%a!eU6];<+E<@L+E2L*<8==?@@ Ms    D9r  r  c                   t        |j                         |      }||k(  r! | t        |      j                               }|S |t        j
                  k(  }|rt        |      }	t        |      }
nt        |      }	t        |      }
t        ||	|
|      j                         } | t        |      j                               }|S )a1  make circle

        Create a circle centered on the origin of plane

        Args:
            radius (float): circle radius
            plane (Plane, optional): base plane. Defaults to Plane.XY.
            start_angle (float, optional): start of arc angle. Defaults to 360.0.
            end_angle (float, optional): end of arc angle. Defaults to 360.
            angular_direction (AngularDirection, optional): arc direction.
                Defaults to AngularDirection.COUNTER_CLOCKWISE.

        Returns:
            Edge: full or partial circle
        )	rZ   	to_gp_ax2r   r   r   COUNTER_CLOCKWISEr   r2   r%  )rs  r   r  start_angle	end_angleangular_direction	circle_gpr[  ccwr  endcircle_geoms               r   make_circlezEdge.make_circle  s    0 EOO-v6	)#6yAFFHIL  $'7'I'IIC,i(	*k*,YsCHNNPK6{CHHJKLr   )r(  c                    y)a  
        Create all planar circular arcs of a given radius that are tangent/contacting
        the two provided objects on the XY plane.
        Args:
            tangency_one, tangency_two
                (tuple[Axis | Edge, PositionConstraint] | Axis | Edge | Vertex | VectorLike):
                Geometric entities to be contacted/touched by the circle(s)
            radius (float): arc radius
            sagitta (LengthConstraint, optional): returned arc selector
                (i.e. either the short, long or both arcs). Defaults to
                LengthConstraint.SHORT.

        Returns:
            ShapeList[Edge]: tangent arcs
        Nr   )rs  tangency_onetangency_twor   r(  s        r   make_constrained_arcszEdge.make_constrained_arcs      r   c                    y)a  
        Create all planar circular arcs whose circle is tangent to two objects and whose
        CENTER lies on a given locus (line/circle/curve) on the XY plane.

        Args:
            tangency_one, tangency_two
                (tuple[Axus | Edge, PositionConstraint] | Axis | Edge | Vertex | VectorLike):
                Geometric entities to be contacted/touched by the circle(s)
            center_on (Axis | Edge): center must lie on this object
            sagitta (LengthConstraint, optional): returned arc selector
                (i.e. either the short, long or both arcs). Defaults to
                LengthConstraint.SHORT.

        Returns:
            ShapeList[Edge]: tangent arcs
        Nr   )rs  r  r  	center_onr(  s        r   r  zEdge.make_constrained_arcs  r  r   c                    y)a<  
        Create planar circular arc(s) on XY tangent to three provided objects.

        Args:
            tangency_one, tangency_two, tangency_three
                (tuple[Axis | Edge, PositionConstraint] | Axis | Edge | Vertex | VectorLike):
                Geometric entities to be contacted/touched by the circle(s)
            sagitta (LengthConstraint, optional): returned arc selector
                (i.e. either the short, long or both arcs). Defaults to
                LengthConstraint.SHORT.

        Returns:
            ShapeList[Edge]: tangent arcs
        Nr   )rs  r  r  tangency_threer(  s        r   r  zEdge.make_constrained_arcs  r  r   c                    y)a  make_constrained_arcs

        Create planar circle(s) on XY whose center is fixed and that are tangent/contacting
        a single object.

        Args:
            tangency_one
                (tuple[Axis | Edge, PositionConstraint] | Axis | Edge | Vertex | VectorLike):
                Geometric entity to be contacted/touched by the circle(s)
            center (VectorLike): center position

        Returns:
            ShapeList[Edge]: tangent arcs
        Nr   )rs  r  r  s      r   r  zEdge.make_constrained_arcs  r  r   c                    y)a  make_constrained_arcs

        Create planar circle(s) on XY that:
        - are tangent/contacting a single object, and
        - have a fixed radius, and
        - have their CENTER constrained to lie on a given locus curve.

        Args:
            tangency_one
                (tuple[Axis | Edge, PositionConstraint] | Axis | Edge | Vertex | VectorLike):
                Geometric entity to be contacted/touched by the circle(s)
            radius (float): arc radius
            center_on (Axis | Edge): center must lie on this object
            sagitta (LengthConstraint, optional): returned arc selector
                (i.e. either the short, long or both arcs). Defaults to
                LengthConstraint.SHORT.

        Returns:
            ShapeList[Edge]: tangent arcs
        Nr   )rs  r  r   r	  s       r   r  zEdge.make_constrained_arcs  r  r   c          
     4   t        |      dkD  r|d   nd }t        |      dkD  r|d   nd }t        |      dkD  r|d   nd }|j                  d|      }|j                  d|      }|j                  d|      }|j                  dd       }|j                  dd       }|j                  d	d       }	|r+t        d
dj                  |j	                                      |||fD 
cg c]  }
|
|
	 }}
g }|D ]  }t        |t              r|j                  t        |             /t        |t              r|j                  |       Qt        |t              rct        |d   t              r+|j                  t        t        |d   |d                      t        |d   t              r|j                  |       t        |t              r(|j                  t        |      |j                  z          	 |j                  t        |              t        |d       }t        |      }d|cxk  rdk  st        d       t        d      ||dk  rt        d      |	t        |	t              rt        |	      }	|dk(  r|||	t!        |||| dS |dk(  r|	||t#        ||	|| dS |dk(  r|||	t%        ||| dS |dk(  r|||	t'        ||| dS |dk(  r|	|t)        ||	|| dS t        d      c c}
w # t        $ r}t        d|      |d }~ww xY w)Nr   r   r   r  r  r  r   r  r	  Unexpected argument(s): , Invalid tangency: c                "    t        | t              S r   )rg  r   xs    r   r   z,Edge.make_constrained_arcs.<locals>.<lambda>p  s    jF6K r   r  r  z Provide 1 to 3 tangency targets.zradius must be > 0.0r'  )r	  r(  r)  )r(  r)  )r  r)  )r	  r   r)  z4Unsupported or ambiguous combination of constraints.)r   popr  joinr  rg  r   r  r   rB  r   r   r  r  r  r   r   r   r   r   r   )rs  r(  argskwargsr  r  r  r   r  r	  ttangency_args
tangenciestangency_argr  	tan_counts                   r   r  zEdge.make_constrained_arcs:  sr    #&d)a-tAwT"%d)a-tAwT$'IMatzz.,?zz.,?$4nEHd+Hd+JJ{D1	 6tyy7O6PQRR %lNC
q}A
 
 CE
) 	PL,-!!$|"45,-!!,/,.l1ot4%%eDa,q/,R&STl1ot4%%l3,/!!&"69N9N"NOP!!&"67)	P2 J,KL

O	I"">?? #>?? &A+344 Z	4%@YI N"!& 	  N%%# 	  >fnIDU"JcRRN"!%z&sSS>i38J(yc  OPPc
2  P"4\4D EFCOPs$    K5(K5/K::	LLLc                     y)aP  
        Create all planar line(s) on the XY plane tangent to two provided curves.

        Args:
            tangency_one, tangency_two
                (tuple[Edge, Tangency] | Axis | Edge):
                Geometric entities to be contacted/touched by the line(s).

        Returns:
            ShapeList[Edge]: tangent lines
        Nr   rs  r  r  s      r   make_constrained_lineszEdge.make_constrained_lines  r  r   c                     y)a  
        Create all planar line(s) on the XY plane tangent to one curve and passing
        through a fixed point.

        Args:
            tangency_one
                (tuple[Edge, Tangency] | Edge):
                Geometric entity to be contacted/touched by the line(s).
            tangency_two (Vector):
                Fixed point through which the line(s) must pass.

        Returns:
            ShapeList[Edge]: tangent lines
        Nr   r  s      r   r   zEdge.make_constrained_lines  r  r   )r  rz  c                    y)a  
        Create all planar line(s) on the XY plane tangent to one curve with a
        fixed orientation, defined either by an angle measured from a reference
        axis or by a direction vector.

        Args:
            tangency_one (Edge): edge that line will be tangent to
            tangency_two (Axis): reference axis from which the angle is measured
            angle : float, optional
                Line orientation in degrees (measured CCW from the X-axis).
            direction : VectorLike, optional
                Direction vector for the line (only X and Y components are used).
            Note: one of angle or direction must be provided

        Returns:
            ShapeList[Edge]: tangent lines
        Nr   )rs  r  r  r  rz  s        r   r   zEdge.make_constrained_lines  r  r   c                   t        |      dkD  r|d   nd}t        |      dkD  r|d   nd}|j                  d|      }|j                  d|      }|j                  dd      }|j                  dd      }|t        |      nd}|duxs |du}|r+t        dd	j	                  |j                                      ||fD cg c]  }||	 }	}t        |	      d
k7  rt        d      g }
t        |	      D ]  \  }}t        |t              r4|dk(  r|r|
j                  |       n|
j                  t        |             Jt        |t              r|
j                  |       lt        |t              r%t        |d   t              r|
j                  |       	 |
j                  t        |              t        |
d       }
||t        |
d   t              rt        |
d   d   t              s!J d       t        |
d   t              sJ d       |t        |      }n$|J t        |j                   |j"                        }t        |
d   t              sJ d       t%        |
d   |
d   ||       S t        |
d   t        t        f      rJ d       t        |
d   t              rJ d       t'        |
d   |
d   |       S c c}w # t        $ r}t        d|      |d}~ww xY w)z
        Create planar line(s) on XY subject to tangency/contact constraints.

        Supported cases
        ---------------
        1. Tangent to two curves
        2. Tangent to one curve and passing through a given point
        r   Nr   r  r  r  rz  r  r  r   z#Provide exactly 2 tangency targets.r  c                .    t        | t        t        f      S r   )rg  r   r   r  s    r   r   z-Edge.make_constrained_lines.<locals>.<lambda>  s    jT6N6S r   r  z*Internal error - 1st tangency must be Edgez-Internal error - 2nd tangency must be an Axis)r)  z7Internal error - 1st tangency can't be an Axis | Vectorz.Internal error - 2nd tangency can't be an Axis)r   r  r   r  r  r  r  rg  r   r  r   rB  r  r  r   r	   YXr   r   )rs  r  r  r  r  r  rz  is_refr  r  r  rB  r  r  ang_rads                  r   r   zEdge.make_constrained_lines  s)    #&d)a-tAwT"%d)a-tAwTzz.,?zz.,?

7D)JJ{D1	)2)>F9%D	d";it&;6tyy7O6PQRR%1<$@RqAMRR}"ABBIK
(7 	POA|,-6f%%l3%%d<&89,-!!,/,.:l1ot3T!!,/P!!&"67	P( J,ST
 	 5*Q-/!qM!$d @?@  "qM4 @?@   !%. ,,,	Y[[91t ?>?  ,1z!}gC  qMD&>
 	ED	E 
 qM4
 	<;	< 
  
1z!}3OOq S*  P"4\4D EFCOPs$   ?J<J<K	K
KKc                   t        |j                  j                         |j                  j	                               }||kD  r5dt
        z  }t        |j                         ||      j                  ||      }	nd}t        |j                         ||      }	||k(  r! | t        |	      j                               }
|
S |t
        z  |z
  }|t
        z  |z
  }|t        j                  k(  r||k  r|dt        z  z  }d}||}}n||k\  r|dt        z  z  }d}||}}t        |	|||      j                         } | t        |      j                               }
|
S )a  make ellipse

        Makes an ellipse centered at the origin of plane.

        Args:
            x_radius (float): x radius of the ellipse (along the x-axis of plane)
            y_radius (float): y radius of the ellipse (along the y-axis of plane)
            plane (Plane, optional): base plane. Defaults to Plane.XY.
            start_angle (float, optional): Defaults to 360.0.
            end_angle (float, optional): Defaults to 360.0.
            angular_direction (AngularDirection, optional): arc direction.
                Defaults to AngularDirection.COUNTER_CLOCKWISE.

        Returns:
            Edge: full or partial ellipse
             V@rn  r   TF)rW   r  r.  r  rA  r   r]   r  Rotatedr   r   r   r  r   r3   r%  )rs  x_radiusy_radiusr  r  r  r  ax1correction_angle
ellipse_gpellipser  a2sensealpha1alpha2ellipse_geoms                    r   make_ellipsezEdge.make_ellipse>  s]   4 U\\((*EKK,>,>,@Ah  $g~!%//"3XxHPP%J  #!%//"3XxHJ)#1*=BBDEG2 - '+;;Bg%)99B $4$F$FF8!b&LB!#R 8!b&LB!#R.FFEeg  1,?DDFGGr   rn  r*  c                    t        |j                         |      }t        ||t        z  |t        z  |t        j
                  k(        j                         } | t        |      j                               }|S )aq  make parabola

        Makes an parabola centered at the origin of plane.

        Args:
            focal_length (float): focal length the parabola (distance from the
                vertex to focus along the x-axis of plane)
            plane (Plane, optional): base plane. Defaults to Plane.XY.
            start_angle (float, optional): Defaults to 0.0.
            end_angle (float, optional): Defaults to 90.0.
            angular_direction (AngularDirection, optional): arc direction.
                Defaults to AngularDirection.COUNTER_CLOCKWISE.

        Returns:
            Edge: full or partial parabola
        )	r_   r  r5   r   r   r  r%  r   r   )	rs  focal_lengthr  r  r  r  parabola_gpparabola_geomparabolas	            r   make_parabolazEdge.make_parabola  so    2 u0,?,'!!1!C!CC	

 %' 	 .}=BBDEr   c                8   t        |j                  j                         |j                  j	                               }||kD  r5dt
        z  }t        |j                         ||      j                  ||      }	nd}t        |j                         ||      }	||k(  r! | t        |	      j                               }
|
S t        |	|t
        z  |z
  |t
        z  |z
  |t        j                  k(        j                         } | t        |      j                               }
|
S )a  make hyperbola

        Makes a hyperbola centered at the origin of plane.

        Args:
            x_radius (float): x radius of the hyperbola (along the x-axis of plane)
            y_radius (float): y radius of the hyperbola (along the y-axis of plane)
            plane (Plane, optional): base plane. Defaults to Plane.XY.
            start_angle (float, optional): Defaults to 360.0.
            end_angle (float, optional): Defaults to 360.0.
            angular_direction (AngularDirection, optional): arc direction.
                Defaults to AngularDirection.COUNTER_CLOCKWISE.

        Returns:
            Edge: full or partial hyperbola
        r*  rn  )rW   r  r.  r  rA  r   r^   r  r+  r   r   r4   r   r  r%  )rs  r,  r-  r  r  r  r  r.  r/  hyperbola_gp	hyperbolahyperbola_geoms               r   make_hyperbolazEdge.make_hyperbola  s   4 U\\((*EKK,>,>,@Ah  $g~"5??#4hIQQ%L  #"5??#4hIL)#3LAFFHII  3g%(88G#&66!%5%G%GG	
 eg  3NCHHJKIr   c                   |dk(  rEt        t        t        |      j                         t        |      j	                               |      }nLt        t        t        |      j                         t        |      j	                               |t        z  |      }|rdnd}	t        |	dz  t        z  |      j                         }
||
j                  z  t        t        |            z  }t        t        dd      t        |
j                  |
j                              }t!        |d|d      }t#        ||      }|j%                         }t'        j(                  |dd	
        | |      S )a  make_helix

        Make a helix with a given pitch, height and radius. By default a cylindrical surface is
        used to create the helix. If the :angle: is set (the apex given in degree) a conical
        surface is used instead.

        Args:
            pitch (float): distance per revolution along normal
            height (float): total height
            radius (float):
            center (VectorLike, optional): Defaults to (0, 0, 0).
            normal (VectorLike, optional): Defaults to (0, 0, 1).
            angle (float, optional): conical angle. Defaults to 0.0.
            lefthand (bool, optional): Defaults to False.

        Returns:
            Wire: helix
        rn  r  r   r   r   T)theAdjustPeriodic&.>i  )
MaxSegment)r<   rY   r   r.  rA  r;   r   r   r  r%  r   r   rB   ra   r\   r&  rC   r   r   r(   r  )rs  pitchheightr   r  rH  r  lefthand	geom_surf	line_signline_dirline_len
helix_linehelix_curveedge_builderr   s                   r   
make_helixzEdge.make_helix  s+   > C<&=vf~,,.v0E0E0GH&'I ,vf~,,.v0E0E0GHI #B	)a-",e4??AXZZ'3wu~+>> !!Q(**hjj1QR
)8t

 /{IF"'') 	TdC;r   c                     | t        t        |      j                         t        |      j                               j                               S )a   Create a line between two points

        Args:
          point1: VectorLike: that represents the first point
          point2: VectorLike: that represents the second point

        Returns:
          A linear edge between the two provided points

        )r   r   r.  r   )rs  point1point2s      r   r  zEdge.make_line	  s?     #v%%')>)>)@df
 	
r   c           
     $   t        |      j                  t        |            }dD cg c]L  }t        j                  |j	                  |      |j	                  |rd|z
  n|            j	                  |      N }}t        j                  | S c c}w )a  make line between edges

        Create a new linear Edge between the two provided Edges. If the Edges are parallel
        but in the opposite directions one Edge is flipped such that the mid way Edge isn't
        truncated.

        Args:
            first (Edge): first reference Edge
            second (Edge): second reference Edge
            middle (float, optional): factional distance between Edges. Defaults to 0.5.

        Returns:
            Edge: linear Edge between two Edges
        )r   r   r   )r   is_oppositer   r  r  )rs  rh  secondr  fliprB  pntss          r   make_mid_wayzEdge.make_mid_way.	  s      E{&&tF|4
 	
  NN!!!$f&8&8$QA&Nk&!"
 
 ~~t$$
s   ABc                   |D cg c]  }t        |       }}|rt        d |D              }	t        dt        |            }
t	        |      D ](  \  }}|
j                  |dz   |j                                * |t        |
||      }nt        |      t        |      |z   k7  r#t        dt        |       dt        |             t        dt        |            }t	        |      D ]  \  }}|j                  |dz   |        t        |
|||      }|rt        	      dk(  r<t        |      dk7  r.|j                  |	d   j                  |	d   j                  |       nt        |	      t        |      k7  r#t        dt        |	       dt        |             t        dt        |	            }t        dt        |	            }t	        |	      D ]I  \  }}|j                  |dz   |du       ||n	t               }|j                  |dz   |j                         K |j                  |||       |j                          |j                         st        d	      |j!                         } | t#        |      j%                               S c c}w )
a  Spline

        Interpolate a spline through the provided points.

        Args:
            points (list[VectorLike]):  the points defining the spline
            tangents (list[VectorLike], optional): start and finish tangent.
                Defaults to None.
            periodic (bool, optional): creation of periodic curves. Defaults to False.
            parameters (list[float], optional): the value of the parameter at each
                interpolation point. (The interpolated curve is represented as a vector-valued
                function of a scalar parameter.) If periodic == True, then len(parameters)
                must be len(interpolation points) + 1, otherwise len(parameters)
                must be equal to len(interpolation points). Defaults to None.
            scale (bool, optional): whether to scale the specified tangent vectors before
                interpolating. Each tangent is scaled, so it's length is equal to the derivative
                of the Lagrange interpolated curve. I.e., set this to True, if you want to use
                only the direction of the tangent vectors specified by `tangents` , but not
                their magnitude. Defaults to True.
            tol (float, optional): tolerance of the algorithm (consult OCC documentation).
                Used to check that the specified points are not too close to each other, and
                that tangent vectors are not too short. (In either case interpolation may fail.).
                Defaults to 1e-6.

        Raises:
            ValueError: Parameter for each interpolation point
            ValueError: Tangent for each interpolation point
            ValueError: B-spline interpolation failed

        Returns:
            Edge: the spline
        c              3  2   K   | ]  }t        |        y wr   )r   )r   r5  s     r   r   z#Edge.make_spline.<locals>.<genexpr>t	  s     #@!F1I#@r  r   NzuThere must be one parameter for each interpolation point (plus one if periodic), or none specified. Parameter count: z, point count: r   r   zgThere must be one tangent for each interpolation point, or just two end point tangents. Tangent count: zB-spline interpolation failed)r   rB  rn   r   r  r  r.  rO   r   rr   Loadr   rm   rq   r   r  r   r   r   )rs  r  r  periodic
parametersr
  tolr  point_vectorstangent_vectorsrY  rB  spline_builderparameters_arrayp_indexp_valuetangents_arraytangent_enabled_arrayt_indext_valuetangent_vecspline_geoms                         r   make_splinezEdge.make_splineG	  s   V 5;;5;;##@x#@@O"1c-&89!-0 	1HAuMM!a%0	1 0xEN:3}#5#@A S:'s=7I6JL 
  5QJH$-j$9 @  ))'A+w?@ 17GSVWN?#q(S-?1-D###A&..0B0J0JE '3}+==$J/0M@R?SU  "4As?7K!L(@s?+)% )2/(B N$GW)227Q;t@ST-4-@'fhK"++GaK9L9LMN
 ##N4I5Q $$&<==$**,*;7<<>??m <s   Jc                   t        |      }|st        d      |D cg c]  }t        |       }}|d   g}	dg}
|dd D ]J  }t        ||	d   z
        t        k  r|
dxx   dz  cc<   )|	j                  |       |
j                  d       L t        dt        |            }t        |d      D ]%  \  }}|j                  ||j                                ' t        dt        |	            }t        |	d      D ]   \  }}|j                  |t        |             " t        dt        |
            }t        |
d      D ]  \  }}|j                  ||        |t        |      ng }|rVt        dt        |            }t        |d      D ]   \  }}|j                  |t        |             " t        ||||||      }nt        |||||      } | t        |      j!                               S c c}w )a9  Create an exact B-spline edge from control points and knot data.

        Args:
            control_points (Iterable[VectorLike]): Control points (poles) defining
                the spline shape.
            knots (Iterable[float]): Knot sequence for the spline. Repeated knot
                values are converted to unique knot values plus multiplicities.
            degree (int): Polynomial degree of the spline.
            weights (Iterable[float] | None, optional): Optional per-control-point
                weights for rational B-splines. Defaults to ``None``.
            periodic (bool, optional): Whether to create a periodic spline.
                Defaults to ``False``.

        Raises:
            ValueError: B-spline requires at least one knot.

        Returns:
            Edge: the B-spline edge
        z#B-spline requires at least one knotr   r   Nr  r  )r  r   r   r  r   r  rl   r   r  r  r.  rp   r~  ro   r:   r   r   )rs  control_pointsknotsdegreer  r^  	knot_listr  ra  unique_knotsmultiplicitiesknotpoles_arrayr   knots_arraymultiplicities_arraymultiplicityweights_listweights_arrayr  rl  s                        r   make_bsplinezEdge.make_bspline	  s   : K	BCC4BC5CC!!~abM 	)D4,r**+y8r"a'"##D)%%a(	) )C,>?%m1= 	8LE5  7	8 +1c,.?@$\; 	5KE4  d4	5  7q#n:MN#,^1#E 	?E< ))%>	? )0(;tG}0C4EFM!*<q!A =v&&ueFm<=+$K ,$K *;7<<>??Y Ds   G,c                   t        dt        |            }t        |      D ]1  \  }}|j                  |dz   t	        |      j                                3 |rt        |g|||d}	nt        ||||      }	|	j                         st        d      |	j                         }
 | t        |
      j                               S )a  make_spline_approx

        Approximate a spline through the provided points.

        Args:
            points (list[Vector]):
            tol (float, optional): tolerance of the algorithm. Defaults to 1e-3.
            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 6.

        Raises:
            ValueError: B-spline approximation failed

        Returns:
            Edge: spline
        r   )DegMaxTol3D)DegMinr~  r  zB-spline approximation failed)rn   r   r  r  r   r.  rP   r  r   r   r   r   )rs  r  r`  	smoothingmin_degmax_degrY  rB  r  rc  rl  s              r   make_spline_approxzEdge.make_spline_approx	  s    8 #1c&k2!&) 	9HAuMM!a%!5!5!78	9 4 )0N 5WWCN $$&<==$**,*;7<<>??r   c                    t        t        |      j                         t        |      j                  t        |      j                               j	                         } | t        |      j                               S )a4  Tangent Arc

        Makes a tangent arc from point start, in the direction of tangent and ends at end.

        Args:
            start (VectorLike): start point
            tangent (VectorLike): start tangent
            end (VectorLike): end point

        Returns:
            Edge: circular arc
        )r2   r   r.  r   r%  r   r   )rs  r  r  r   r  s        r   make_tangent_arczEdge.make_tangent_arc)
  s_      )5M  "F7O$;$;VC[=O=O=Q

%' 	 *;7<<>??r   c                    t        t        |      j                         t        |      j                         t        |      j                               j                         } | t	        |      j                               S )a6  Three Point Arc

        Makes a three point arc through the provided points

        Args:
            point1 (VectorLike): start point
            point2 (VectorLike): middle point
            point3 (VectorLike): end point

        Returns:
            Edge: a circular arc through the three points
        )r2   r   r.  r%  r   r   )rs  rS  rT  point3r  s        r   make_three_point_arczEdge.make_three_point_arc?
  sb      )6N!!#VF^%:%:%<fVn>S>S>U

%' 	 *;7<<>??r   c                Z    | j                   st        | g      j                         }|S | }|S )zClose an Edge)rS  r   close)rN  r[  s     r   r  z
Edge.closeW
  s2    ~~<--/L   Lr   c                    |dk  rt        d      t        |      D cg c]  }||||z
  z  |dz
  z  z    }}| j                  |      }|r|D ]  }t        ddd      |_         |S c c}w )a6  Distribute Locations

        Distribute locations along edge or wire.

        Args:
          self: Wire:Edge:
          count(int): Number of locations to generate
          start(float): position along Edge|Wire to start. Defaults to 0.0.
          stop(float): position along Edge|Wire to end. Defaults to 1.0.
          positions_only(bool): only generate position not orientation. Defaults to False.

        Returns:
          list[Location]: locations distributed along Edge|Wire

        Raises:
          ValueError: count must be two or greater

        r   zcount must be two or greaterr   r   )r   r9  rP  r   orientation)	rN  r  r  stoppositions_onlyrB  t_valuesrP  rL  s	            r   distribute_locationszEdge.distribute_locations`
  s    2 19;<<FKElSEA.%!)<<SSNN8,	  2"(Aq/2  Ts   A&c                8   | j                   t        d      | j                  t        j                  k7  rt        d      | j                  d      }| j                  d      }t        t        t        j                  | j                  ||            }|j                         }t        |      D cg c]  }|j                  |dz          }	}|r| dfndd|z   f}
|r'| j                  |       j!                         }|g|	z   }	n(| j                  d|z         j!                         }|	|gz   }	|
D cg c]  }| j#                  |       }}|	D cg c]  }t%        |       }}t&        j)                  ||      }|j                  J t        j                  |j                  |j                  d      |j                  d            }t+        j,                  ||      }|t/        d      t'        t1        |      j'                               }||fS c c}w c c}w c c}w )zCHelper method to slightly extend an edge that is bound to a surfacezCan't extend empty splinez&_extend_spline only works with splinesr   r   )r  z'Failed to snap extended edge to surface)rQ  r   r  r   BSPLINEr  r;  r  r:   r   Curve_sr   NbPolesr9  Poler  r.  r  r   r   rm  rV   	Project_sr  r   )rN  at_startgeom_surfaceextension_factoru_startu_endcurve_originaln_polesrB  r  endsnew_poler  r  rY  extended_edge
geom_curvesnapped_geom_curvesnapped_edges                      r   _extend_splinezEdge._extend_spline
  s    == 899>>X---DEEq)}}Q'y00wN
 !((*5:7^D$$QU+DD)1!!1%1?O;O7P'')9(9:AACHJ&E'',<(<=DDFHXJ&EBF%GQdooa&8%G%G5:!;&)!;!;(((A$$000&&!!=#9#9!#<m>T>TUV>W

 )22:|L%HII 34FGLLNO///3 E &H!;s   .H.HHc           
        | j                   t        d      t        |t              rt	        t
        |j                        }| j                         j                  t        |      j                               }t        j                  ||j                  d|j                  z  z  z   ||j                  |j                  z  z         }| j                  |      }|t        d      t        |j                         j#                         }t%        j&                  |      }t%        j(                  | j                   |t+               | j-                  d      | j-                  d            }|c|j                   Wt%        j(                  |j                   |t+               |j-                  d      |j-                  d            }	t/        ||	|      }
nt/        ||      }
t1        |
j3                               D cg c]N  }t        |
j5                  |dz         j7                         |
j5                  |dz         j9                               P }}|D cg c]  }|j;                  |       }}g }|D ]p  }	 |B| j=                  |      t>        k  rS|j=                  |      t>        k  r;|jA                  |       n)| j=                  |      t>        k  r|jA                  |       r tC        |      S c c}w c c}w # t        $ r Y w xY w)a  find_intersection_points

        Determine the points where a 2D edge crosses itself or another 2D edge

        Args:
            other (Axis | Edge): curve to compare with
            tolerance (float, optional): the precision of computing the intersection points.
                 Defaults to TOLERANCE.

        Raises:
            ValueError: empty edge

        Returns:
            ShapeList[Vector]: list of intersection points
        z&Can't find intersections of empty edger  z%All objects must be on the same planer   r   )"rQ  r   rg  r   r  r   r  r  addr   r   r  rz  r-  r  r   r   r   r   	Surface_sCurveOnPlane_srw   r;  rD   r9  r  Pointr&  r%  from_local_coordsr  r   r  r   )rN  r  r  posself_bbox_w_edger  	pln_shapeedge_surfaceself_2d_curveedge_2d_curveintersectorrB  crossesr  valid_crossesrJ  s                   r   find_intersection_pointszEdge.find_intersection_points
  s   $ == EFF eT"/C#00266vc{7O7O7QRNNeoo.>.G.G)GHHeoo(8(A(AAAE
 !!%(=DEE+EMM:??A	 **95&/&>&>LLMM!MM!'
 !:*3*B*B!q!q!+M 4}iK 4M9MK ;//12
 ;$$QU+--/1B1B1q51I1K1K1MN
 

 8??!5**1-??  	C$((-:!--c2i?%,,S1'',	9%,,S1	 ''1

 @   s    0AK%	K*+A-K//	K;:K;c                d   |dz  }| j                   t        j                  k(  r| j                  d      |k(  rdg}|S g }|S t	        | j
                        }g }d}d}t        d|z
        D ]^  }| j                  |dz        |dz  z   }|(t        ||z
        dkD  rt        d||z
        }|d|z  z  }|}|j                  |dz  |f       ` t        j                  |      }	|	j                         }
dt        |
j                  j                  dz        z  }dt!        |
j"                  j                  dz        z  }g }t        ||d	z   d      D ]D  }t        j%                  d||z   dfd||z   df      }|j'                  |	j)                  |             F |D cg c]  }|j*                   }}|S c c}w )
zfind_tangent

        Find the parameter values of self where the tangent is equal to angle.

        Args:
            angle (float): target angle in degrees

        Returns:
            list[float]: u values between 0.0 and 1.0
        r  r   Nrn  e   r  i,  r  r   )r  r   r  r  r}  rS  r9  r  r   r  r   rm  r  r   r  r%  r
   r  r  r  r  r&  )rN  r  r  r^  tan_pntsprevious_tangentdiscontinuitiesrB  r  	tan_curvetan_curve_bbox	min_range	max_rangeintercept_pntsr  r  s                   r   find_tangentzEdge.find_tangent  s     >>X]]*$$Q'503N K J E 4>>*H)+H# "O3>* 	4//C8?S;PP$0,w67#=&.s4Dw4N&OOs_44G#* S' 23	4 ((2I '335Nu^%7%7%9%9C%?@AItN$6$6$8$83$>?@I ,.N9i!mS9 P~~q%!)Q&7#uqy!9LM%%i&H&H&NOP &444H4 5s   F-c                Z    | j                   t        d      t        | j                        S )z$Return the Geom Curve from this Edgez!Can't find adaptor for empty edge)rQ  r   r   r   rM  s    r   rf  zEdge.geom_adaptorC  s'    == @AA ..r   c                (   t        |t              sy| j                  |j                  k7  ry| dz  |dz  k7  s| dz  |dz  k7  ry| j                         }|j                         }| j                  xt        j
                  k(  r yxt        j                  k(  r |j                         |j                         }}t        |j                         |j                         z
        |k  xr t        |j                               t        |j                               k(  xrO t        |j                         j                               t        |j                         j                               k(  S xt        j                  k(  r |j                         |j                         }	}t        |j!                         |	j!                         z
        |k  xr t        |j#                         |	j#                         z
        |k  xr t        |j                               t        |	j                               k(  xrO t        |j                         j                               t        |	j                         j                               k(  S xt        j$                  k(  r |j'                         |j'                         }}
t        |
j!                         |j!                         z
        |k  xr t        |
j#                         |j#                         z
        |k  xr t        |
j                               t        |j                               k(  xrO t        |
j                         j                               t        |j                         j                               k(  S xt        j(                  k(  r |j+                         |j+                         }}t        |j-                         |j-                         z
        |k  xr t        |j                               t        |j                               k(  xrO t        |j                         j                               t        |j                         j                               k(  S xt        j.                  k(  r  |j1                         |j1                         }}|j3                         |j3                         k7  s!|j5                         |j5                         k7  ryt7        d|j5                         dz         D ]{  }t        |j9                  |            t        |j9                  |            k7  r y|j;                         sKt        |j=                  |      |j=                  |      z
        |k\  s{ y yxt        j>                  k(  r |jA                         |jA                         }}|j3                         |j3                         k7  ry|jC                         |jC                         k7  ry|j5                         |j5                         k7  s!|jE                         |jE                         k7  ryt7        d|j5                         dz         D ]{  }t        |j9                  |            t        |j9                  |            k7  r y|j;                         sKt        |j=                  |      |j=                  |      z
        |k\  s{ y t7        d|jE                         dz         D ]X  }t        |jG                  |      |jG                  |      z
        |k\  r y|jI                  |      |jI                  |      k7  sX y yt        jJ                  k(  r|jM                         |jM                         }}t        |jO                         |jO                         z
        |k\  ryt        |j                               t        |j                               k7  ryt        tQ        |jS                               j                               }t        tQ        |jS                               j                               }|jU                  ||      S 	 t7        d|dz         D ]  }||dz   z  }| |z  ||z  k7  s y y)aK  Compare two edges for geometric equality within tolerance.

        This compares the geometric properties of two edges, not their topological
        identity. Two independently created edges with the same geometry will
        return True.

        Args:
            other: Edge to compare with
            tol: Tolerance for numeric comparisons. Defaults to 1e-6.
            num_interpolation_points: Number of points to sample for unknown
                curve types. Defaults to 5.

        Returns:
            bool: True if edges are geometrically equal within tolerance
        Fr   r   T)+rg  r   r  rf  r   r  rS  rj  r  rk  r   r   r   rT  rU  rV  MajorRadiusMinorRadius	HYPERBOLA	HyperbolaPARABOLAParabolaFocalBEZIERBezierDegreer  r9  r  
IsRationalWeightr  BSpline
IsPeriodicNbKnotsKnotMultiplicityOFFSETOffsetCurveOffsetr   
BasisCurve
geom_equal)rN  r  r`  num_interpolation_pointsga1ga2c1c2e1e2h1h2p1p2b1b2rB  s1s2oc1oc2basis1basis2r  s                           r   r  zEdge.geom_equalI  sX   , %& >>U__, 1H%!)$uqy(A!  "nn szz|B		biik12S8 Wr{{}-1FFWrwwy2245	@S@S@U9VV "!!B(2>>+;;<sB WBNN,r~~/??@3FWr{{}-1FFW rwwy2245	@S@S@U9VV	 $###--/B(2>>+;;<sB WBNN,r~~/??@3FWr{{}-1FFW rwwy2245	@S@S@U9VV	 #""B
RXXZ/036 Wr{{}-1FFWrwwy2245	@S@S@U9VV !szz|B99;"))+-1M q"**,"23 %Abggaj)VBGGAJ-??$}}3ryy|biil/J+Ks+R$	%
 !!!B99;"))+- ==?bmmo5 ::<2::</2::<2::<3O q"**,"23 %Abggaj)VBGGAJ-??$}}3ryy|biil/J+Ks+R$	%
 q"**,"23 %A2771:
23s:$q)R__Q-??$	%
 ??,coo.?Sszz|cjjl23s: #--/*fS]]_.EE 5cnn6FGLLNO5cnn6FGLLNO((55 q":Q">? %A59:Aqeai0$% r   c                d   | j                         }t        j                  |      }|t        j                  k(  r| j
                  sd|z
  }|}n*| j
                  s| j                  |z
  }|| j                  z  }t        |||z  |j                               j                         }||| j
                  fS )aZ  
        Map a position on this edge to its underlying OCCT parameter.

        This returns the OCCT `BRepAdaptor_CompCurve` for the edge together with
        the corresponding (non-normalized) curve parameter at the given position.
        The interpretation of `position` depends on `position_mode`:

        - ``PositionMode.PARAMETER``: `position` is a normalized curve parameter in [0, 1].
        - ``PositionMode.DISTANCE``: `position` is an arc length distance along the edge.

        Edge orientation (`is_forward`) is taken into account so that positions are
        measured consistently along the geometric curve.

        Args:
            position (float): Position along the edge, either a normalized parameter
                (0-1) or a distance, depending on `position_mode`.
            position_mode (PositionMode, optional): How to interpret `position`.
                Defaults to ``PositionMode.PARAMETER``.

        Returns:
            tuple[BRepAdaptor_CompCurve, float, bool]: The curve adaptor for this edge,
            the corresponding OCCT curve parameter and is_forward.
        r   )	rf  r6   Length_sr   r9  rV  r  r$  r  )rN  r  r  r  r  r  r  s          r   r  zEdge._occt_param_at  s    4 &&(
%..z:L222??x<E??;;1t{{*E)
(A(A(C

)+ 	 :t66r   c                    | j                         }t        j                  |      }t        |||z  |j                               j	                         S )u  
        Map a normalized arc-length position to the underlying OCCT parameter.

        Returns the native OCCT curve parameter corresponding to the
        given normalized `position` (0.0 → start, 1.0 → end). For closed/periodic
        edges, OCCT may return a value **outside** the edge's nominal parameter
        range `[param_min, param_max]` (e.g., by adding/subtracting multiples of
        the period). If you require a value folded into the edge's range, apply a
        modulo with the parameter span.

        Args:
            position (float): Normalized arc-length position along the shape,
                where `0.0` is the start and `1.0` is the end. Values outside
                `[0.0, 1.0]` are not validated and yield OCCT-dependent results.

        Returns:
            float: OCCT parameter (for edges) **or** composite “edgeIndex + fraction”
            parameter (for wires), as described above.

        )rf  r6   r  r$  r  )rN  r  r&  r  s       r   r;  zEdge.param_at  sK    , !!#%..u5#6H$e&:&:&<

)+	r   c           
          j                   t        d      t        |      t        j                   j
                        \  }}||z
  }t         j                         fd      }t        |      z
  j                  t        k  r||j
                  pt        j                  |j
                   j
                        }t         j
                        }t        j                  |||      }|t        j                  |      z  }|S  j                        }	t        |	dt              st        d d|	 d      t        j                    j
                  t#               t#                     }
t%        j'                         |
      }|j)                         }t         j
                        }|j+                         r|||z
  |j-                         z  z   }t        j                  |||      }|t        j                  |      z  } j/                  |      z
  j                  t        k  r|S d	}t1        |      D ]  }d
|z  }d|z  }t1        |      D ]  }||z  |dz   |z  }}t3         fd||fddt        d
z  i      }|j4                   |j6                  t        z   z   |j6                  t        z
  z  z
  j                  k  sst9        t#        |j6                        t:              c c S   t=        d      )u!  
        Return the normalized parameter (∈ [0.0, 1.0]) of the location on this edge
        closest to `point`.

        This method always returns a **normalized** parameter across the edge's full
        OCCT parameter range, even though the underlying OCP/OCCT queries work in
        native (non-normalized) parameters. It is robust to several OCCT quirks:

        1) Vertex snap (fast path)
        If `point` coincides (within tolerance) with one of the edge's vertices,
        that vertex's OCCT parameter is used and normalized to [0, 1].
        Note: for a closed edge, a vertex may represent both start and end; the
        mapping is therefore ambiguous and either end may be chosen.

        2) Projection via GeomAPI_ProjectPointOnCurve
        The OCCT projector's `LowerDistanceParameter()` can legitimately return a
        value **outside** the edge's [param_min, param_max] (e.g., periodic curves
        or implementation behavior). The result is wrapped back into range using a
        modulo by the parameter span and then normalized to [0, 1]. The projected
        answer is accepted only if re-evaluating the 3D point at that normalized
        parameter is within tolerance of the input `point`.

        3) Fallback numeric search (robust path)
        If the projector fails the validation, a bounded 1D search is performed
        over [0, 1] using progressive subdivision and local minimization of the
        3D distance ‖edge(u) - point‖. The first minimum found under geometric
        resolution is returned.

        Args:
            point (VectorLike): A point expected to lie on this edge (within tolerance).

        Raises:
            ValueError: If `point` is not on the edge within tolerance.
            ValueError: Can't find param on empty edge
            RuntimeError: If no parameter can be found (e.g., extremely pathological
                curves or numerical failure).
        Returns:
            float: Normalized parameter in [0.0, 1.0] corresponding to the point's
            closest location on the edge.
        zCan't find param on empty edgec                4    t        |       z
  j                  S r   )r   r  )r5  rJ  s    r   r   z%Edge.param_at_point.<locals>.<lambda>F  s    VAY_<T<T r   r  r   r  point () is z
 from edger  r   r  r   c                @    j                  |       z
  j                  S r   )r  r  )r  rJ  rN  s    r   r   z%Edge.param_at_point.<locals>.<lambda>  s    t//2S8@@ r   boundedxatol)boundsmethodoptionsz-Unable to find parameter, Edge is too complex)rQ  r   r   r   Range_sr   r  r   r  r   Parameter_sr   r6   r  r  r   r  r~  rQ   r.  LowerDistanceParameterr  Periodr  r9  r   funr  roundr   r  )rN  r  	param_min	param_maxparam_rangenearest_vertexrE  curve_adaptorr  
separationr&  r  max_divisionsdivision	intervalssteprB  lohir  rJ  s   `                   @r   r  zEdge.param_at_point  s   R == =>>Um(00>	9)+ T]]_2TU>"S(
&I"0"8"8"D)).*@*@$,,OE-dll;M*33M9eTG+44]CCGN%%c*
Q	:wse5JGHH !!$,,A/

eD	002 *$,,7##%%)"3}7K7K7M!MNE&//y%P'00?? W%+33i?N" m, 	>H8I?D9% >TAET>B(@8$$i!m4	 JJ9 459@T8UUf
 !vxx*==#>		>. JKKr   c                Z    t        |       j                  |||      }|j                         S )a  Project Edge

        Project an Edge onto a Shape generating new wires on the surfaces of the object
        one and only one of `direction` or `center` must be provided. Note that one or
        more wires may be generated depending on the topology of the target object and
        location/direction of projection.

        To avoid flipping the normal of a face built with the projected wire the orientation
        of the output wires are forced to be the same as self.

        Args:
          target_object: Object to project onto
          direction: Parallel projection direction. Defaults to None.
          center: Conical center of projection. Defaults to None.
          target_object: Shape:
          direction: VectorLike:  (Default value = None)
          center: VectorLike:  (Default value = None)

        Returns:
          : Projected Edge(s)

        Raises:
          ValueError: Only one of direction or center must be provided

        )r   project_to_shaper   )rN  target_objectrz  r  projected_wiress        r   r  zEdge.project_to_shape  s,    > t*55mYPVW$$&&r   c                ,   | j                   t        d      t        | j                   t              sJ t	        j
                  |       }|r| j                  d      }| j                  d      }t        j                  | j                   ||      }|j                  |      }|j                  |      }t        |j                         ||      j                         }||_        |S t        j                  | j                  j                               |_        |S )a  reversed

        Return a copy of self with the opposite orientation.

        Args:
            reconstruct (bool, optional): rebuild edge instead of setting OCCT flag.
                Defaults to False.

        Returns:
            Edge: reversed
        zAn empty edge can't be reversedr   r   )rQ  r   rg  rz   r/  r0  r;  r   r  ReversedParameterr   Reversedr   r   rx   )rN  reconstructreversed_edgerh  lastr&  r   s          r   reversedzEdge.reversed  s     == >??$--555d+==+E--*D%%dmmUDAE++E2E**40D1%..2BD%PUUWK$/M!  %+KK0E0E0G$HM!r   zYto_axis is deprecated and will be removed in a future version.  Use 'Axis(Edge)' instead.c                    | j                   t        j                  k7  rt        d| j                          t	        | j                  d      | j                  d      | j                  d      z
        S )z"Translate a linear Edge to an Axisz+to_axis is only valid for linear Edges not r   r   )r  r   r  r   r   r  rM  s    r   to_axiszEdge.to_axis  sf     >>X]]*=dnn=MN  D$$Q')9)9!)<t?O?OPQ?R)RSSr   zYto_wire is deprecated and will be removed in a future version.  Use 'Wire(Edge)' instead.c                    t        | g      S )zEdge as Wire)r   rM  s    r   to_wirezEdge.to_wire  s     TF|r   c           
        t         j                  | |d      }t         j                  | |d      }| j                  |      }| j                  |      \  }}}| j                  |      \  }	}
}t	        t        t        j                  | j                  |j                         |j                               gt        ||
g       j	                               }|j                  d      |z
  j                  t        k  }| j                  |      j                  |j                  d            dt        z
  kD  }|r|r|S |j!                  d      S )a  trim

        Create a new edge by keeping only the section between start and end.

        Args:
            start (float | VectorLike): 0.0 <= start < 1.0 or point on edge
            end (float  | VectorLike): 0.0 < end <= 1.0 or point on edge

        Raises:
            TypeError: invalid input, must be float or VectorLike
            ValueError: can't trim empty edge

        Returns:
            Edge: trimmed edge
        r  r   r   r   T)r  )rK  r  r  r  r   r   r   r  r   r$  r#  r  r  r   r  dotr  )rN  r  r   start_uend_ur  comp_curve_start
parm_startrF  _comp_curve_endparm_endtrimmed_edge
same_startsame_directions                 r   rm  z	Edge.trim  s>   $ ##D%9!!$U3&&w/ +/*=*=g*F'*a'+':':5'A$1 #!!LL$335$224 X./ df	
 #..q1K?GG)S
OOG$(()@)@)CDq9}T 	 .$$$66r   c                   | j                   t        d      t        j                  | |d      }t	        j
                  |       }|j                  J t        j                  |j                  | j                  d      | j                  d            }t        |      }| j                  |      }t        |||      }|j                         }	t        |||	      }
t        |
      j                         }t        |      S )al  trim_to_length

        Create a new edge starting at the given normalized parameter of a
        given length.

        Args:
            start (float | VectorLike): 0.0 <= start < 1.0 or point on edge
            length (float): target length

        Raise:
            ValueError: can't trim empty edge

        Returns:
            Edge: trimmed edge
        zCan't trim empty edger  r   r   )rQ  r   rK  r  r/  r0  r   r   r  r;  rN   r6   r  r@   r   r   )rN  r  r  r  	self_copy	new_curveadaptor_curver  abscissa_pointr!  trimmed_curvenew_edges               r   r  zEdge.trim_to_length  s      == 455##D%9MM$'	  ,,,%%t}}Q/q1A
	
 *)4 ]]7+
-mVZP "++- *)ZJ*=9>>@H~r   c           	     (   t        |t              rt        |      n|}| j                  |      }|sy|j	                         }t        |D cg c]  }| j                  d|       c}      }|j                  t        j                        d   }|S c c}w )zQReturn the shortest Edge of self trimmed by other or None if they don't intersectNr   )
rg  r   r   r  r   r   rm  sort_byr   r  )rN  r  	other_objintersectionsintersection_pntsrJ  
self_trimsshortest_trimmed_selfs           r   trim_to_otherzEdge.trim_to_otherD  s     &0x%@F5Me	 y1 *224 =NOc		!S 1OP
 !+ 2 24;; ? B$$  Ps   Bc                ^    | j                   t        j                  k(  xr | j                  dkD  S )z5Check if edge is infinite (LINE with length > 1e100).g}Ô%IT)r  r   r  r  rM  s    r   r+  zEdge.is_infinite]  s%     ~~.F4;;3FFr   c                    | j                   s| S | j                         }| j                         | j                         z
  j	                         }t
        j                  |||z  z
  |||z  z         S )a  Trim an infinite line edge to a finite length.

        OCCT's boolean operations struggle with very long edges (length > 1e100).
        This method trims such edges to a reasonable size centered at edge.center().

        For non-infinite edges, returns self unchanged.

        Args:
            half_length: Half-length of the resulting edge

        Returns:
            Trimmed edge if infinite, otherwise self
        )r+  r  r(  r  r  r   r  )rN  half_lengthr  rz  s       r   r,  zEdge.trim_infiniteb  sk     K^^%(8(8(::FFH	~~Y,,Y,,
 	
r   )N NN)rt  z TopoDS_Edge | Axis | None | Noner  r   r  Color | Noner  Compound | Noner  )rt  r   rz  r   r  r   )r  r   r  list[float] | Noner  r   )r   r~  r  r   r  r~  r  r~  r  r   r  r   )
r  @tuple[Axis | Edge, Tangency] | Axis | Edge | Vertex | VectorLiker  r;  r   r~  r(  r   r  r   )
r  r;  r  r;  r	  zAxis | Edger(  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  #tuple[Edge, Tangency] | Axis | Edger  r<  r  r   )r  tuple[Edge, Tangency] | Edger  r   r  r   )
r  r=  r  r   r  r  rz  r  r  r   r  r   )r,  r~  r-  r~  r  r   r  r~  r  r~  r  r   r  r   )r9  r~  r  r   r  r~  r  r~  r  r   r  r   ))r   r   r   r  rn  F)rG  r~  rH  r~  r   r~  r  r   rH  r   r  r~  rI  r  r  r   )rS  r   rT  r   r  r   )r  )rh  r   rW  r   r  r~  r  r   )NFNTr  )r  list[VectorLike]r  zlist[VectorLike] | Noner^  r  r_  r:  r
  r  r`  r~  r  r   )NF)ro  Iterable[VectorLike]rp  r  rq  r}  r  r  r^  r  r  r   )r  Nr      )r  r?  r`  r~  r  z!tuple[float, float, float] | Noner  r}  r  r}  r  r   )r  r   r  r   r   r   r  r   )rS  r   rT  r   r  r   r  r   )r  r  )rn  r  F)rN  zWire | Edger  r}  r  r~  r  r~  r  r  r  r  )g?)r  r  r  r?   r  r~  )r  zAxis | Edge | Noner  r~  r  zShapeList[Vector])r  r~  r  zlist[float])r  r   r     )r  r   r`  r~  r  r}  r  r  r  r~  r  r   r  z%tuple[BRepAdaptor_Curve, float, bool]r  r~  r  r~  r  r   r  r~  NN)r  r   rz  r  r  r  r  r   F)r  r  r  r   )r  r   r  r   )r  r  r   r  r  r   )r  r  r  r~  r  r   )rN  r   r  z,Shape | Axis | Location | Plane | VectorLiker  Edge | Noner  )r6  r~  r  r   )8r   r   r   r   r  r  r  rc  r  r{  r  r   r   r   r  r  r   r   SHORTr  r   r7  r=  rB  rQ  r  rZ  rm  r|  r  r  r  r  r  r  r   r  r  rf  r  r   r9  r  r;  r  r  r  r   r  r  rm  r  r3  r+  r,  __classcell__r  s   @r   r   r     s2	    E
 15""&
-
 
 	

  
B  " P P& CG.A#.A.@.A	.A .A`  xx".>.P.P%% % 	%
 % ,% 
% %N  #==V W
   
  0  #==V W
   
  2  #==V W
 M  
  2 V 	
 
  * V 	
  
  8 
 #==hQ hQ
 
hQ hQT 9 : 
	  " 2  
	  (  #'+2 
  % 
  4 PP PPd 
 xx" .>.P.P@@ @ 	@
 @ @ ,@ 
@ @D  xx .>.P.P"" " 	"
 " ," 
" "H 
 xx" .>.P.P22 2 	2
 2 2 ,2 
2 2h  '&> >  >  	> 
 >  >  >  >  
>  > @ 
 
" % %0  -1)-`@ `@ *`@ 	`@
 '`@ `@ `@ 
`@ `@D  +/L@,L@ L@ 	L@
 (L@ L@ 
L@ L@\  7;-@ -@ -@ 5	-@
 -@ -@ 
-@ -@^ @@)3@:D@	@ @* @@)3@=G@	@ @. $### # 	#
 # 
#R #&	,0,0 #,0  	,0^ +/9R('R(;@R(	R(h:: 
:x/ ()	}} } #&	}
 
}@ >J=S=S)7)7.:)7	.)7V:ALL (,$(	 ' ' % ' "	 '
 
 'D> 	%T	T 	%	.7`*X%%;% 
%2 G G
r   c                  <    e Zd ZdZdZe	 	 	 d%	 	 	 	 	 	 	 d&d       Ze	 	 	 d%	 	 	 	 	 	 	 d'd       Ze	 	 	 d%	 	 	 	 	 	 	 d(d       Ze	 	 	 d%	 	 	 	 	 	 	 d)d       Ze	 	 	 	 d*	 	 	 	 	 	 	 	 	 d+d       Z fdZed,d-d	       Ze	 d.	 	 	 	 	 d/d
       Z	ed0d       Z
eej                  fd1d       Zed2d3d       Zeej                  ddej                   df	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d4d       Zed5d6d       Zeej                  f	 	 	 	 	 	 	 d7d       Ze	 	 	 	 	 	 d8d       Z	 d9	 	 	 	 	 	 	 	 	 d:dZd;dZd<dZd=dZd>dZd?dZd<dZ	 	 d@	 	 	 	 	 	 	 dAdZdBdZdCdZe jB                  f	 	 	 	 	 dDdZ"	 	 dE	 	 	 	 	 	 	 dFdZ#dGd Z$dHd!Z% e&d"      d;d#       Z'dId$Z( xZ)S )Jr   ax  A Wire in build123d is a topological entity representing a connected sequence
    of edges forming a continuous curve or path in 3D space. Wires are essential
    components in modeling complex objects, defining boundaries for surfaces or
    solids. They store information about the connectivity and order of edges,
    allowing precise definition of paths within a 3D model.g      ?c                     y)a'  Build a wire from an OCCT TopoDS_Wire

        Args:
            obj (TopoDS_Wire, optional): OCCT Wire.
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr   )rN  rt  r  r  r  s        r   r  zWire.__init__  r  r   c                     y)a  Build a Wire from an Edge

        Args:
            edge (Edge): Edge to convert to Wire
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr   )rN  r   r  r  r  s        r   r  zWire.__init__  r  r   c                     y)aP  Build a Wire from an Wire - used when the input could be an Edge or Wire.

        Args:
            wire (Wire): Wire to convert to another Wire
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr   rN  r   r  r  r  s        r   r  zWire.__init__  r  r   c                     y)a  Build a Wire from an Curve.

        Args:
            curve (Curve): Curve to convert to a Wire
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr   rR  s        r   r  zWire.__init__  r  r   c                     y)aw  Build a wire from Edges

        Build a Wire from the provided unsorted Edges. If sequenced is True the
        Edges are placed in such that the end of the nth Edge is coincident with
        the n+1th Edge forming an unbroken sequence. Note that sequencing a list
        is relatively slow.

        Args:
            edges (Iterable[Edge]): Edges to assemble
            sequenced (bool, optional): arrange in order. Defaults to False.
            label (str, optional): Defaults to ''.
            color (Color, optional): Defaults to None.
            parent (Compound, optional): assembly parent. Defaults to None.
        Nr   )rN  r   	sequencedr  r  r  s         r   r  zWire.__init__  r  r   c           	        d\	  }}}}}}}	}
}|rt        |      }t        |d   t              r|d d dd|z
  z  z   \  }}	}
}nt        |d   t              r|d d dd|z
  z  z   \  }}	}
}nt        |d   t              r|d d dd|z
  z  z   \  }}	}
}nt        |d   d      rLt        |d   j                  t              r/t        |d   j                        dk(  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|
      }
|j                  d|      }|j                  d|      }|j                  d|      }||g}n||j!                         }||j                  }n|rt        j#                  ||dn|      }t$        | M  ||	dn|	|
|       y )N)	NNNNNNNNNr      r   r   r   rC  r  )	r&  r   r   r   rU  rt  r  r  r  zUnexpected argument(s) rt  r   r   rU  r  r  r  r   r&  Fr7  r  )r   rg  r~   r   r   hasattrr   ry   r   r   r  r  r  
differencer   getr   
_make_wirer  r  )rN  r  r  r&  r   r   r   rU  rt  r  r  r  l_aunknown_argsr  s                 r   r  zWire.__init__  s   ITFtUD)S%d)C$q';/,0!Hw!c'7J,J)UE6DGT*-1"1X1s78K-K*eUFDGT*-1"1X1s78K-K*eUFQ+tAw@tAw/14.22AhAG9L.L+ueVDGX.9=bqGqSVwDW9W6y%yy))

 6|nEFFjj$zz&$'

7E*JJ{I6	

7E*

7E*Hf-zz&$'

7E*FEKKME,,C//%)2CSC"5	 	 	
r   c                   dd}t        |      }|r^|j                  d      g}|}|rF |t        |      |      }|j                  |      }|j	                  |j                  |             |rF|}t               }t               }	|D ]*  }
|
j                  |	j                  |
j                         , |j                  |	       |j                          |j                         s|j                         t        k(  r't        j                  dd       |j                         S |j                         t         k(  rt#        d      |j                         t$        k(  rt'        d      |j                         S )	ah  _make_wire

        Build a Wire from the provided unsorted Edges. If sequenced is True the
        Edges are placed in such that the end of the nth Edge is coincident with
        the n+1th Edge forming an unbroken sequence. Note that sequencing a list
        is relatively slow.

        Args:
            edges (Iterable[Edge]): Edges to assemble
            sequenced (bool, optional): arrange in order. Defaults to False.

        Raises:
            ValueError: Edges are disconnected and can't be sequenced.
            RuntimeError: Wire is empty

        Returns:
            Wire: assembled edges
        c                P    | j                  d      t        |fd      }|d   S )z/Return the Edge closest to the end of last_edger   c                    t        | j                  d      z
  j                  | j                  d      z
  j                        S )Nr   r   )r  r  r  )r   target_points    r   r   z9Wire._make_wire.<locals>.closest_to_end.<locals>.<lambda>?  s:    c!AMM!$44<<!AMM!$44<< r   r  r   )r  r  )currentunplaced_edgessorted_edgesra  s      @r   closest_to_endz'Wire._make_wire.<locals>.closest_to_end9  s1    "..q1L!L  ?"r   r   z8Wire is non manifold (e.g. branching, self intersecting)r   )
stacklevelzWire is emptyzEdges are disconnected)rb  r   rc  z
list[Edge]r  r   )r  r  r   r   r  r!   r   r   r=  r>  r?  r  Errorr"   warningswarnr   r  r   r   )rs  r   rU  re  placed_edgesrc  	next_edgenext_edge_indexrF  rE  r   s              r   r[  zWire._make_wire$  sV   *	# U!IIaL>L"N *4+=~N	"0"6"6y"A##N$6$6$GH !
 !E.0-/ 	4D||'%%dll3	4 	(""$!!#'EEN    "" ##%)AA"?33##%)HH !9::  ""r   c                   t               }t               }|D cg c]  }|j                         D ]  }|  c}}D ]*  }|j                  |j                  |j                         , t	        j
                  ||d|       t               }t        |j                               D ]E  }|j                  t        t        t        t        |j                  |dz                                  G |S c c}}w )a
  combine

        Combine a list of wires and edges into a list of Wires.

        Args:
            wires (Iterable[Wire |  Edge]): unsorted
            tol (float, optional): tolerance. Defaults to 1e-9.

        Returns:
            ShapeList[Wire]: Wires
        Fr   )r   r   r   r=  rh   ConnectEdgesToWires_sr   r9  Lengthr  r   r  r~   r   r%  )	rs  rz  r`  edges_in	wires_outr{  r   r   rB  s	            r   combinezWire.combineg  s      -.-/	 %91qwwy9!Q9Q9 	.D||'-	. 	!66xeYWy'')* 	UALLeK)//!a%:P1QRST	U  :s   C.c                    t        d      )z$extrude - invalid operation for Wirez#Wires can't be created by extrusionr   ry  s      r   r{  zWire.extrude  s     >??r   c                H    t         j                  ||      }t        |g      S )zmake_circle

        Makes a circle centered at the origin of plane

        Args:
            radius (float): circle radius
            plane (Plane): base plane. Defaults to Plane.XY

        Returns:
            Wire: a circle
        )r  )r   r  r   )rs  r   r  circle_edges       r   r  zWire.make_circle  s&     &&vU&;[M""r   c                   t        |      }t        d|z        }i }g }t        |      D ]V  \  }}t        |      D ]C  }||dz
  z  }	|j	                  t        |j                  |	            dd        ||	f|||z  |z   <   E X t        |      }
g }i }|
j                  D ]+  }||d      d   }||d      d   }||k7  r|||vr
|d   g||<   n||   j	                  |d          ||vr
|d   g||<   n||   j	                  |d          |j	                  |||d      d   |d   f|||d      d   |d   ff       t        |d   |d   z
        dk7  st        |j                               }t        |j                               }||vr||g||<   n||   j                  ||g       |j	                  |||   d   |f|||   d   |ff       . i }|j                         D ]d  \  }}t        |      }g }t        dt!        |      dz
  d      D ]1  }||   ||dz      k7  s|j	                  t        |||dz                 3 |||<   f |D cg c]<  }t"        j%                  ||d   d      |d   d   z  ||d   d      |d   d   z        > }}|j                         D cg c]3  \  }}|D ])  }||   j'                  ||d      d   ||d      d         + 5 }}}}t)        ||z   d      }|S c c}w c c}}}w )a  make_convex_hull

        Create a wire of minimum length enclosing all of the provided edges.

        Note that edges can't overlap each other.

        Args:
            edges (Iterable[Edge]): edges defining the convex hull
            tolerance (float): allowable error as a fraction of each edge length.
                Defaults to 1e-3.

        Raises:
            ValueError: edges overlap

        Returns:
            Wire: convex hull perimeter
        r   r   Nr   T)rU  )r  r}  r  r9  r  rB  r  r   	simplicesr  r  tolistr  r  itemsr  r   r   r  rm  r   )rs  r   r  fragments_per_edgepoints_lookupr  
edge_indexr   rB  rE  convex_hullconnecting_edge_datatrim_pointssimplicer  r  	start_pntend_pnt	trim_datastart_end_pntss_pointsf_pointsr  connecting_edges
trim_pairs	trim_pairtrimmed_edges	hull_wires                               r   make_convex_hullzWire.make_convex_hull  s   T U Y/ !*% 0 	YJ-. Y/!34eD$4$4U$;<Ra@AFPRWEXj+==ABY	Y !(  ",.#--  	H!(1+.q1E!(1+.q1E~+*21+K&&--hqk:+*21+K&&--hqk:$++hqk :1 =x{Khqk :1 =x{K Xa[8A;./14 12	hoo/0+*3W)=K&&--y'.BC$++i 8 ;YGg 6q 97C7 	D 	*5*;*;*= 	-&Jn-HH1c(ma/3 @A;(1q5/1OOE(1q1u*=$>?@ %-Ij!	- -	
  NNd1gaj!DGAJ.d1gaj0ADGAJ0N
 
 +4//*;	
 
 '
J'

 	 *""il+A.il0KA0N

 
 )M9TJ	

s   	AK. 8K3r  Tc                    t         j                  ||||||      }||k7  rC|rAt         j                  |j                         |j	                               }	t        ||	g      }
|
S t        |g      }
|
S )a  make ellipse

        Makes an ellipse centered at the origin of plane.

        Args:
            x_radius (float): x radius of the ellipse (along the x-axis of plane)
            y_radius (float): y radius of the ellipse (along the y-axis of plane)
            plane (Plane, optional): base plane. Defaults to Plane.XY.
            start_angle (float, optional): _description_. Defaults to 360.0.
            end_angle (float, optional): _description_. Defaults to 360.0.
            angular_direction (AngularDirection, optional): arc direction.
                Defaults to AngularDirection.COUNTER_CLOCKWISE.
            closed (bool, optional): close the arc. Defaults to True.

        Returns:
            Wire: an ellipse
        )r   r7  r  r(  r  r   )rs  r,  r-  r  r  r  r  rt  ellipse_edger  r   s              r   r7  zWire.make_ellipse  sy    8 ((h{I?P
 )#>>,"8"8":L<T<T<VWDt,-D  'Dr   c                ,   |D cg c]  }t        |       }}|d   |d   z
  j                  t        kD  r|r|j                  |d          t	               }|D ]!  }|j                  |j                                #  | |j                               S c c}w )a  make_polygon

        Create an irregular polygon by defining vertices

        Args:
            vertices (Iterable[VectorLike]):
            close (bool, optional): close the polygon. Defaults to True.

        Returns:
            Wire: an irregular polygon
        r   r  )r   r  r   r  r   r>  r.  r   )rs  r   r  r5  vectorsrF  r   s          r   make_polygonzWire.make_polygon9  s     '//6!9//AJ$,,y8UNN71:&13 	.FV]]_-	. <$$&'' 0s   Bc                    |dz  |dz  f|dz  |dz  f|dz  |dz  f|dz  |dz  fg}|D cg c]  }|j                  |       }}t        j                  |d      S c c}w )aS  Make Rectangle

        Make a Rectangle centered on center with the given normal

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

        Returns:
            Wire: The centered rectangle
        r   T)r  )r  r   r  )rs  widthrH  r  corners_localr}  corners_worlds          r   	make_rectzWire.make_rectP  s    ( QY
#QY$RZ"%RZ!$	
 >KK003KK  d ;; Ls   Ac                N    | r"|\  }}|| k(  r||fS || k(  r||fS t        d      |S )z9Order the edges of a chamfer relative to a reference Edgezreference edge not in edgesrt  )reference_edger   r  edge2s       r   order_chamfer_edgeszWire.order_chamfer_edgesm  sE    
  LE5&e|#&e|#:;;r   c                   | j                   t        d      |}t        | j                        }t	        |      }t               }t        j                  |t        j                  t        j                  |       |D ]  }	|	s|j                  |	j                        }
t        t        t        t        |
j!                                           t        t        t        t        |
j#                                           f}t$        j'                  ||      \  }}|j                  |j                  |j)                  t+        j                  |j                        t+        j                  |j                        ||        |j-                          |j/                         }t1        |      }|j3                          t        |j/                               }t5        |t6              st9        d      t%        t;        j<                  |            S )a  chamfer_2d

        Apply 2D chamfer to a wire

        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

        Returns:
            Wire: chamfered wire
        zCan't chamfer empty wirez.An internal error occured creating the chamfer)rQ  r   r   r   r&   r   ru   MapShapesAndAncestors_sr  rq  r  FindFromKeyr   r  rz   r   FirstLastr   r  
AddChamferrx   r?  r   ri   r   rg  r{   r  r.   OuterWire_s)rN  rC  	distance2r   r   r  unchamfered_facechamfer_buildervertex_edge_mapr5  	edge_listr   r  r  chamfered_face	shape_fixs                   r   
chamfer_2dzWire.chamfer_2d}  s   * == 788 8E45EFCE&&b..	
  	A'33AII>I
 U;1B(CDEU;1A(BCDE
  33NEJLE5}}(U]]-F**KK.KK.		* 	(..0">2	!)//"34.+6OPPI)).9::r   c                    | j                   sNt        j                  | j                         | j	                               }t
        j                  | |f      d   }|S | }|S )zClose a Wirer   )rS  r   r  r(  r  r   rr  )rN  r   r[  s      r   r  z
Wire.close  sU    ~~>>$.."2D4D4D4FGD<<t5a8L   Lr   c                8   t        | j                        }t               }|j                         rjt	        |j                               }| j                  | n| j                  |_        |j                  |       |j                          |j                         rj|S )z#edges - all the edges in this Shape)	r/   r   r   r  r   r  topo_parentr  r  )rN  r  r  rk  s       r   r   z
Wire.edges  s     *$,,7%.[	mmoX--/0I ((0d6F6F ! Y'MMO mmo r   c                   | j                   t        d      | j                         }|t        d|        |j                  |       }|D ]x  }|j                  |      }|j	                         j                  |      d   }t        |      t        |      z
  j                  t        kD  rt        d|       t        |||      }z |j                  |      }|j                  }	t        | j                   j                               }
|
j                         |	z  }|j                  j                         }|j                  j!                  t#                     }t%        j&                  t)        ||d      j+                               }t'        |      }t        | j                   j                               |_        | j,                  |j,                  k7  r|j                  j/                          |S )a+  fillet_2d

        Apply 2D fillet to a wire

        Args:
            radius (float):
            vertices (Iterable[Vertex]): vertices to fillet

        Raises:
            RuntimeError: Internal error
            ValueError: empty wire

        Returns:
            Wire: filleted wire
        zCan't fillet an empty wirezWire is not planar r   z&Could not find fillet vertex on wire: T)rQ  r   r  to_local_coordsr   r-  r   r  r   rI  r  locationr   inverser   TransformationLocatedrw   rx   r   r#   r   rV  r;  )rN  r   r   wire_plnfilleted_wirer   vertex_localcurrent_vertexglobalized_filleted_wireold_locnew_locgeometry_adjusttrsf	base_wiretransformed
final_wires                   r   	fillet_2dzWire.fillet_2d  s     == 9::$$&24&9:: !006 	WF#33F;L*335FF|TUVWN~&)==EE	Q #I&!RSS/~vVM	W *2)C)CM)R  +334==1134!//+g5&&557,44<<_=NO	kk$Yd;AAC
 +&
&t}}'='='?@
 ??j333&&(r   c           	     >   | j                   t        d      t        | j                        }|j	                  |       |j                  d       |j                          |j                          t        t        t        t        |j                                           S )zfix_degenerate_edges

        Fix a Wire that contains degenerate (very small) edges

        Args:
            precision (float): minimum value edge length

        Returns:
            Wire: fixed wire
        zCan't fix an empty edger  )rQ  r   rj   r   SetPrecisionSetMaxToleranceFixSmallEdgesFixWireGapsr   r  r~   r   r   )rN  	precisionsf_ws      r   fix_degenerate_edgeszWire.fix_degenerate_edges  sy     == 677!$,,/)$T"E+x

'=>??r   c                Z    | j                   t        d      t        | j                        S )z(Return the Geom Comp Curve for this Wirez$Can't get geom adaptor of empty wire)rQ  r   r   r   rM  s    r   rf  zWire.geom_adaptor%  s'    == CDD$T\\22r   c                   | j                         j                  |       }t        |d   g      }|dd D ]S  }|d   }t        |dz  |dz  z
        t        k  r|j                  |       5|j                  |j                                U |S )zBReturn the edges in self ordered by wire direction and orientationr   r   Nr  )r   r-  r   r  r   r  r  )rN  rd  ordered_edgesr   	last_edges        r   order_edgeszWire.order_edges,  s     zz|++D1!<?"34 $ 	6D%b)I9q=4!8+,y8$$T*$$T]]_5	6 r   c                    t        |t              sy| j                         }|j                         }t        |      t        |      k7  ryt	        fdt        ||      D              S )aY  Compare two wires for geometric equality within tolerance.

        This compares the geometric properties of two wires by comparing their
        constituent edges pairwise. Two independently created wires with the
        same geometry will return True.

        Args:
            other: Wire to compare with
            tol: Tolerance for numeric comparisons. Defaults to 1e-6.
            num_interpolation_points: Number of points to sample for unknown
                curve types. Defaults to 5.

        Returns:
            bool: True if wires are geometrically equal within tolerance
        Fc              3  J   K   | ]  \  }}|j                  |        y wr   )r  )r   r  r  r  r`  s      r   r   z"Wire.geom_equal.<locals>.<genexpr>X  s+      
B MM"c#;<
s    #)rg  r   r  r   r  r  )rN  r  r`  r  edges1edges2s     ``  r   r  zWire.geom_equal;  sd    * %& !!#""$v;#f+% 
ff-
 
 	
r   c                x   | j                         }| j                  |      }t        |j                         |      }|j	                         r|j                         dk(  rt        d      t        d      }d}d}t        d|j                         dz         D ]Y  }|j                  |      }	|	|k  s|	}|j                  |      j                         }|j                  |      j                         }[ |-t        t        t        |            |z
  j                   t"        kD  rt        d      t        t        |      S )u   
        Return the OCCT comp-curve parameter corresponding to the given wire position.
        This is *not* the edge composite parameter; it is the parameter of the wire’s
        BRepAdaptor_CompCurve.
        r   zFailed to find point on curver   Nr   )rf  r  r1   r.  r  NbExtr  r~  r9  SquareDistancer  r%  r  r   r  r`   r  r   )
rN  r  r&  
target_pntextremar  closest_pntclosest_paramrB  r  s
             r   r;  zWire.param_at]  s    !!# %%h/
  
 1 1 3U;~~7==?a#7>??<q'--/A-. 	=A))!,Dh%mmA.446 'a 0 : : <	= uV[12Z?GG)S>??UM**r   c                   | j                   t        d      t        |      }t        |      }|j                  J | j                  |      }t        |dt              st        d| d| d      t        |j                  | j                        }|j                          |j                         r|j                         dk(  rt        d      |j                  d      }|t        j                  k(  r=t        t         t#        |j%                  d                  }|j'                  d      d   }n|t        j(                  k(  rt        t*        t#        |j%                  d                  }	t-               }
t/        j0                  | j                  t2        j4                  t2        j6                  |
       t        t         t#        |
j9                  |	      j;                                     }t=        j>                  |	|      }tA              }t=        jB                  |      \  }}|jE                         r|z
  |jG                         z  |z   }|jI                         tJ        jL                  k(  r|fn|f}tO        jP                  |g| }tS        | j                        }|jU                         r|jW                         }t=        jX                  |      r|j[                          F|j]                  |      rnB|tO        jP                  tA        |            z  }|j[                          |jU                         r|| j^                  z  S )	a  
        Return the normalized wire parameter for the point closest to this wire.

        This method projects the given point onto the wire, finds the nearest edge,
        and accumulates arc lengths to determine the fractional position along the
        entire wire. The result is normalized to the interval [0.0, 1.0], where:

        - 0.0 corresponds to the start of the wire
        - 1.0 corresponds to the end of the wire

        Unlike the edge version of this method, the returned value is **not**
        an OCCT curve parameter, but a normalized parameter across the wire as a whole.

        Args:
            point (VectorLike): The point to project onto the wire.

        Raises:
            ValueError: Can't find point on empty wire

        Returns:
            float: Normalized parameter in [0.0, 1.0] representing the relative
            position of the projected point along the wire.
        zCan't find point on empty wirer   r  r  r  z
 from wirezpoint is not on Wirer   )0rQ  r   r   r   r   r  r   r   r$   r   r  
NbSolutionSupportTypeShape2r%   BRepExtrema_IsOnEdger  rz   r   SupportOnShape2ParOnEdgeS2BRepExtrema_IsVertexr}   r   ru   r  r  rq  r  r  r  r   r  r   r  r  r  r:  rs   rU  r6   r  r/   r  r  Degenerated_sr  IsEqualr  )rN  r  r  vertex_on_curver  r  	supp_typeclosest_topods_edgeclosest_topods_edge_paramv_hitr  r  r  r   
param_pairdistance_along_wirewire_explorerr   s                     r   r  zWire.param_at_point  s   0 == =>> 0&&222%%e,
Q	:wugU:,jIJJ,_-D-DdllS~~7#5#5#71#<344--a0	/DDD"'Xg&=&=a&@A# )0(;(;A(>q(A%1FFF-'2I2I!2L)MNEGIO**b.. #(Xo&A&A%&H&N&N&PQ# )2(=(=*)% **=>(001DE	9##%*Y6-:N:N:PP)%
 #..04F4U4UU 12+Y7 	
 3;;MWJW /t||<  "'//1K&&{3""$""#67#7#@#@!+.$      " #T[[00r   c                   |t         j                  k(  r!| j                  sd|z
  }|| j                  z  }n| j                  s| j                  |z
  }|}| j	                         }|D cg c]  }|j                   }}g }d}|D ]  }	||	z  }|j                  |        |dk  rd}
d}n9||k\  rt        |      dz
  }
||
   }n t        ||      }
|
dkD  r||
dz
     nd}||z
  }||
   }|j                  dk(  rdn||j                  z  }|j                  sd|z
  }|j                  |      }|j                         }|||j                  fS c c}w )a  
        Map a position along this wire to the underlying OCCT edge and curve parameter.

        Unlike the edge version, this method determines which constituent edge of the
        wire contains the requested position, then returns a curve adaptor for that
        edge together with the corresponding OCCT parameter.

        The interpretation of `position` depends on `position_mode`:

        - ``PositionMode.PARAMETER``: `position` is a normalized parameter in [0, 1]
        across the entire wire.
        - ``PositionMode.DISTANCE``: `position` is an arc length distance along the wire.

        Edge and wire orientation (`is_forward`) is respected so that positions are
        measured consistently along the wire.

        Args:
            position (float): Position along the wire, either a normalized parameter
                (0-1) or a distance, depending on `position_mode`.
            position_mode (PositionMode, optional): How to interpret `position`.
                Defaults to ``PositionMode.PARAMETER``.

        Returns:
            tuple[BRepAdaptor_Curve, float]: The curve adaptor for the specific edge
            at the given position, the corresponding OCCT parameter on that edge and
            if edge is_forward.
        r  rn  r   r   )
r   r9  rV  r  r   r  r   r   r;  rf  )rN  r  r  rC  
self_edgesr   edge_lengthscumulative_lengthstotaledge_lengthedge_idx
local_distprev_cumtarget_edge
local_fracr  r  s                    r   r  zWire._occt_param_at  s}   > L222??>$++-H??;;1H ZZ\
*45Q55' 	-K[ E%%e,	-
 s?HJ:*H%h/J#$6AH;Ca<)(Q,7SH!H,J * %%*Ck>P>P1P 	 %%ZJ &..z:(557!?K4J4JJJA 6s   &Ec                   | j                   |st        d      |&|$t        |      j                         }t               }n||d}t        |      }nt        d      |(t	        | j
                  |j
                  t        |       }n't	        | j
                  |j
                  t        |       }t               }| j
                  j                         }|j                         r|j                         }	||	j                         k(  r|j                  t        |	             n?|j                  t        t        t        t!        |	j#                                                  |j%                          |j                         rt'        j(                  dt+        |             t+        |      dkD  rg }
| j-                         }|D ]}  }|j-                         }|I||z
  j                         }|j/                  |      dk\  s=|
j                  |||z
  j0                  f       ^|
j                  |||z
  j0                  f        |
j3                  d        t'        j(                  d	t+        |
             t        |
D cg c]  }|d   	 c}      }t        |D cg c]  }|j5                          c}      }|S c c}w c c}w )
a  Project Wire

        Project a Wire onto a Shape generating new wires on the surfaces of the object
        one and only one of `direction` or `center` must be provided. Note that one or
        more wires may be generated depending on the topology of the target object and
        location/direction of projection.

        To avoid flipping the normal of a face built with the projected wire the orientation
        of the output wires are forced to be the same as self.

        Args:
          target_object: Object to project onto
          direction: Parallel projection direction. Defaults to None.
          center: Conical center of projection. Defaults to None.
          target_object: Shape:
          direction: VectorLike:  (Default value = None)
          center: VectorLike:  (Default value = None)

        Returns:
          : Projected wire(s)

        Raises:
          ValueError: Only one of direction or center must be provided

        Nz,Can't project empty Wires or to empty Shapesz*Provide exactly one of direction or centerz!wire generated %d projected wiresr   r   c                    | d   S )Nr   r   r  s    r   r   z'Wire.project_to_shape.<locals>.<lambda>  s
    ad r   r  z8projected, filtered and sorted wire list is of length %d)rQ  r   r   r  r-   r   r[   r`   r   r:  r  r  r  r   r  r~   r   r  r  r   debugr   r  r  r  sortr  )rN  r  rz  r  direction_vectorcenter_pointprojection_objectoutput_wirestarget_orientationprojected_wireoutput_wires_distancesplanar_wire_centeroutput_wireoutput_wire_centeroutput_wire_directionr{  cleaned_wiress                    r   r  zWire.project_to_shape'  s   @ == KLL V^%i0;;=!8LI$5#!&>LIJJ ' 3%%()! !4%%%! )2!\\557$$&.668N!^%?%?%AA##D$89##{H^5L5L5N,OPQ ""$  $$& 	8#l:KL
 |q %'"!%+ %0%7%7%9"#/*-?? jl * -001ABaG.55 +!36H!H P P +11'/,>FF* #''N';LLJ*+ %4J%Kqad%KLL "l"C1779"CD &L #Ds   >J:J?c                r   | j                   |st        d      t               }|j                  t	        j
                  | j                               |j                  t	        j
                  |j                               |j                          | j                  j                  |j                               S )zAttempt to stitch wires

        Args:
            other (Wire): wire to combine

        Raises:
            ValueError: Can't stitch empty wires

        Returns:
            Wire: stitched wires
        zCan't stitch empty wires)
rQ  r   r!   r>  rx   r   r   r?  r  r   )rN  r  rF  s      r   stitchzWire.stitch  s     == 788.0T\\23U]]34~~""<#4#4#677r   c                   t               }| j                  t        d      t        | j                        }|j                         r|j                         }t        j                  |      r|j                          Ft        j                  |      \  }}t        j                  |t               t                     }t        |||      }|j                  |t              }|st!        d      |j                          |j                         rt#        |j%                               }	|	j'                         st!        d      t)        |	j)                               S )u0  
        Collapse this wire into a single BSpline edge (internal use).

        Concatenates the wire's constituent edges—**in topological order**—into one
        `Geom_BSplineCurve` using OCP/OCCT's `GeomConvert_CompCurveToBSplineCurve`.
        Degenerate edges are skipped. The resulting topology is a **single Edge**;
        former junctions between original edges become **internal spline knots**
        (C0 corners) but **not vertices**.

        ⚠️ Not intended for general user workflows. The loss of vertex boundaries
        can make downstream operations (e.g., splitting at vertices, continuity checks,
        feature recognition) surprising. This is primarily useful for internal tasks
        that benefit from a single-curve representation (e.g., length/abscissa queries
        or parameter mapping along the entire wire).

        Behavior & caveats:
        - Orientation and section order follow the wire's topological sequence.
        - Junctions with only C0 continuity are preserved as spline knots, not as
            topological vertices.
        - The returned edge's parameterization is that of the composite BSpline
            (not a normalized [0,1] wire parameter).
        - Failure to append any segment or to build the final edge raises an error.

        Raises:
            RuntimeError: If any segment cannot be appended to the composite spline
                or the final BSpline edge cannot be built.
            ValueError: Empty Wire

        Returns:
            Edge: A single edge whose geometry is `GeomType.BSPLINE`.
        zCan't convert an empty wirezFailed to build bspline.)rR   rQ  r   r/   r   r  r  r   r  r  r  r  r~  r@   r>  r   r  r   BSplineCurver  r   )
rN  builderr  r   r  r   r'  r*  okrP  s
             r   _to_bsplinezWire._to_bspline  s   B 67== :;;.t||<  "'//1K&&{3""$#,#4#4[#A Iy!))+uwHI-iINM ]I6B"#=>>    "  /w/C/C/EF""$9::L%%'((r   zYto_wire is deprecated and will be removed in a future version.  Use 'Wire(Wire)' instead.c                    | S )zGReturn Wire - used as a pair with Edge.to_wire when self is Wire | Edger   rM  s    r   r  zWire.to_wire  s	     r   c                   t         j                  | |d      }t         j                  | |d      }t        ||g      \  }}| j                         j	                  |       }t        |      dk(  r#|d   }|j                  ||      }t        |g      S | j                  }||z  }	||z  }
g }d}|D ]  }|j                  }|}||z   }|}||	k  s||
k\  r#||	k\  r||
k  r|j                  |       ?t        |	|      }t        |
|      }||z
  |z  }||z
  |z  }t        ||z
        t        kD  s}|j                  |j                  ||              t        |      S )a5  Trim a wire between [start, end] normalized over total length.

        Args:
            start (float | VectorLike): normalized start position (0.0 to <1.0) or point
            end (float | VectorLike): normalized end position (>0.0 to 1.0) or point

        Returns:
            Wire: trimmed Wire
        r  r   r   r   rn  )rK  r  r  r   r-  r   rm  r   r  r  r  r  r  r   )rN  r  r   r  r  r  ordered_edget_edgetotal_length	start_lenend_lenr  
cur_lengthr   edge_len
edge_startedge_endtrim_start_lentrim_end_lenu0u1s                        r   rm  z	Wire.trim  s~    ##D%9!!$U3% 01 

,,T2 }"(+L!&&w6F>!{{l*	,&
! 	<D{{H#J!H,H!J9$
g(=Y&8w+>$$T* "%Y
!;"7H5$z1X="Z/8;rBw<)+!((2r):;)	<, M""r   )r7  NN)rt  r~   r  r   r  r8  r  r9  )r   r   r  r   r  r8  r  r9  )r   r   r  r   r  r8  r  r9  )r   r   r  r   r  r8  r  r9  )Fr7  NN)
r   Iterable[Edge]rU  r  r  r   r  r8  r  r9  rH  )r   r  rU  r  r  r~   )rE  )rz  zIterable[Wire | Edge]r`  r~  r  ShapeList[Wire])rt  r   rz  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   rt  r  r  r   r  )r   r@  r  r  r  r   )r  r~  rH  r~  r  r   r  r   )r  rJ  r   tuple[Edge, Edge]r  r  r   )
rC  r~  r  r~  r   Iterable[Vertex]r   rJ  r  r   rI  r>  )r   r~  r   r  r  r   )r  r~  r  r   )r  r   rB  )r  r   r`  r~  r  r}  r  r  rE  rF  rD  rG  )r  r   rz  r  r  r  r  r  )r  r   r  r   )r  r   )rN  r   r  r  r   r  r  r   )*r   r   r   r   r  r   r  r  r[  rr  r{  r   r   r  r  r   r  r7  r  r  r  r  r  r  r   r  r  rf  r  r  r;  r  r   r9  r  r  r  r  r   r  rm  rL  rM  s   @r   r   r   |  sE   ? E  ""&  	
      ""&  	
      ""&  	
      ""&  	
       ""&  	
    .>
D @# @#D 8<)05	 < @ @ 7<xx # # s sj 
 xx" .>.P.P%% % 	%
 % % ,% % 
% %N ( (, 
 xx	<< < 	<
 
< <8 #,=	 ( !A;A; A; #	A;
 A; 
A;F 4l@*3$ ()	 
 
  
 #&	 

 
 
D +DZ1z >J=S=SJKJK.:JK	.JK^ (,$(	nn %n "	n
 
n`8,:)x 	%	5#r   c                   t               }t               }| D ]*  }|j                  |j                  |j                         , t        j                  ||d|       t               }t        |j                               D ]A  }|j                  t        t        j                  |j                  |dz                            C |S )zConvert edges to a list of wires.

    Args:
      edges: Iterable[Edge]:
      tol: float:  (Default value = 1e-6)

    Returns:

    Fr   )r   r   r=  rh   rn  r   r9  ro  r  r   rx   r%  )r   r`  rp  rq  r   rz  rB  s          r   ro  ro  )  s     )*H)+I *<<#OODLL)* 228S%S&[E9##%& @T&++iooa!e&<=>?@ Lr   c                    t               }|j                  | |t               |j                          |j	                         S )zOffset a topods_face)r  Tol)r+   r  r   MakeOffsetShaper   )r5  amountoffsetors      r   rZ  rZ  D  s8    $&HV;>>r   c           
        t         t        j                  t        t        j                  t
        t        j                  t        t        j                  t        t        j                  i}||n| j                  }|t        d      | st        d      | j                  }t               }|j                         D cg c]  }|j                  |j                   }}|D ]  }|j                  |      rt        ||      }	|	$|	j                  1t!        j"                  |	j                  |      }
t!        j"                  |	j                  |      }t%        |      }t%        |      }t'        j(                  |||
|t*        t*              }|j-                  |t        j                        }||k\  s|j/                  |        t1        d |D              S c c}w )a~  
    Find edges connected to the given edge with at least the requested continuity.

    Args:
        edge: The reference edge to explore from.
        parent: Optional parent Shape. If None, uses edge.topo_parent.
        continuity: Minimum required continuity (C0/G0, C1/G1, C2/G2).

    Returns:
        ShapeList[Edge]: Connected edges meeting the continuity requirement.
    edge has no valid parentzedge is emptyc              3  2   K   | ]  }t        |        y wr   r  r  s     r   r   z/topo_explore_connected_edges.<locals>.<genexpr>  s     6T!W6r  )rE   r   C0rK   C1rF   rL   C2rG   r  r   r   r  r   r   r   r   r  r   r*   Continuity_sr   rZ  r  r   )r   r  
continuitycontinuity_mapgiven_topods_edger   r   topods_edgesr   common_topods_vertexr  u2curve1curve2actual_continuityactual_levels                   r   topo_explore_connected_edgesr7  M  s   " 	O&&O&&O&&O&&O&&N )Vt/?/?F~344))eO (.||~O!9NAIIOLO# 1##K0.H{/
 !,$,,8 &&';'C'CEVWB&&';'C'C[QB ''89F&{3F !* 6 6B	9! *--.?ASASTLz)##K071: 6o666? Ps   9GGc           	     0   | st        d      ||n| j                  }|st        d      t               }t        j                  |j
                  t        j                  t        j                  |       t               }g }|j                  | j
                        r1|j                  | j
                        D ]  }|j                  |        t        |j                               D ]/  }|j                  t!        j"                   ||dz                      1 |S )zMGiven an edge extracted from a Shape, return the topods_faces connected to itz Can't explore from an empty edger'  r   )r   r  r   ru   r  r   r  r  TopAbs_FACEr   Containsr  r>  r9  Extentr  rx   r   )r   r  edge_face_mapunique_face_mapunique_facesr5  rB  s          r   rY  rY    s    
 ;<<)Vt/?/?F344 >?M
""
 12OLdll+!--dll; 	&D%	&?))+, AFKKA(>?@A r   )r   r   r   r   r  r   )r   r   r   r~  r  z_WireFilletSolution | None)r   rz   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~  r  r  )r5  r{   r$  r~  r  r|   )r   r   r  Shape | Noner-  r   r  r   r   )r   r   r  r?  r  zlist[TopoDS_Face](
  r   
__future__r   r/  rh  bisectr   collections.abcr   r   dataclassesr   	itertoolsr   mathr	   r
   r   r   r   r   r   r   r   typingr   r   r  r   numpyr  
OCP.TopAbsTopAbsr  OCP.BOPAlgor   OCP.BRepr   OCP.BRepAdaptorr   r   OCP.BRepAlgoAPIr   r   OCP.BRepBuilderAPIr   r   r   r   r   r    r!   r"   r#   OCP.BRepExtremar$   r%   OCP.BRepFilletAPIr&   OCP.BRepGPropr'   OCP.BRepLibr(   r)   OCP.BRepLPropr*   OCP.BRepOffsetr+   OCP.BRepOffsetAPIr,   OCP.BRepProjr-   OCP.BRepToolsr.   r/   
OCP.ChFi2dr0   OCP.Extremar1   OCP.GCr2   r3   r4   r5   
OCP.GCPntsr6   r7   r8   OCP.Geomr9   r:   r;   r<   r=   r>   r?   r@   
OCP.Geom2drA   rB   rC   OCP.Geom2dAPIrD   OCP.GeomAbsrE   rF   rG   rH   rI   rJ   rK   rL   rM   OCP.GeomAdaptorrN   OCP.GeomAPIrO   rP   rQ   OCP.GeomConvertrR   OCP.GeomFillrS   rT   rU   OCP.GeomProjLibrV   OCP.gprW   rX   rY   rZ   r[   r\   r]   r^   r_   r`   ra   rb   rc   	OCP.GProprd   OCP.HLRAlgore   OCP.HLRBReprf   rg   OCP.ShapeAnalysisrh   OCP.ShapeFixri   rj   OCP.Standardrk   
OCP.TColgprl   rm   rn   OCP.TColStdro   rp   rq   rr   rs   rt   
OCP.TopExpru   rv   
OCP.TopLocrw   
OCP.TopoDSrx   ry   rz   r{   r|   r}   r~   OCP.TopToolsr   r   r   r   scipy.optimizer   scipy.spatialr   typing_extensionsr   r   build123d.build_enumsr   r   r   r   r   r   r   r   r   r   build123d.geometryr   r   r   r   r   r   r   r   r   r   constrained_linesr   r   r   r   r   r   r   
shape_corer   r   r   r   r   r   r   r   r   utilsr   r   r   zero_dr   r   	compositer   r   r   r   three_dr   two_dr   r   r   r   r   r   r   r  r%  r7  rG  rI  rK  r   r   ro  rZ  r)  r7  rY  r   r   r   <module>r~     s  1f #    . ! " M M M        (  D
 
 
 P 8 # 4 # 0 6 , ; ( %  
	 	 	 
 4
 
 
 . 
 @ 
 (    # ) 8 6 ; 3 R R  < . &    + $ .      
 
 
 R Q 688" $& & & $$ $ $6',<-:	$3<##',##L#%#%)<#%	#%L8"bKeFm bKJ!r
7; r
j;j#7; j#Z%6  "1"4"4?7
?7?7  ?7 	?7F (,
$r   