
    ^jt/                       d Z ddlmZ ddlmZmZmZmZ ddlm	Z	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ ddlmZ ddlmZ ddl m!Z! ddl"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4m5Z5 e
rddl6m7Z7 ddl8m9Z9m:Z: d!dZ;	 d"	 	 	 	 	 	 	 d#dZ<	 d$	 	 	 	 	 d%dZ=d&dZ>d'dZ?d(d)dZ@d*dZAd+dZBd,dZCd-d ZDy).a9  
build123d topology

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

desc:

This module provides utility functions and helper classes for the build123d CAD library, enabling
advanced geometric operations and facilitating the use of the OpenCascade CAD kernel. It complements
the core library by offering reusable and modular tools for manipulating shapes, performing Boolean
operations, and validating geometry.

Key Features:
- **Geometric Utilities**:
  - `polar`: Converts polar coordinates to Cartesian.
  - `tuplify`: Normalizes inputs into consistent tuples.
  - `find_max_dimension`: Computes the maximum bounding dimension of shapes.

- **Shape Creation**:
  - `_make_loft`: Creates lofted shapes from wires and vertices.
  - `_make_topods_compound_from_shapes`: Constructs compounds from multiple shapes.
  - `_make_topods_face_from_wires`: Generates planar faces with optional holes.

- **Boolean Operations**:
  - `new_edges`: Identifies newly created edges from combined shapes.

- **Enhanced Math**:
  - `isclose_b`: Overrides `math.isclose` with a stricter absolute tolerance.

This module is a critical component of build123d, supporting complex CAD workflows and geometric
transformations while maintaining a clean, extensible API.

license:

    Copyright 2025 Gumyr

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

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

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

    )annotations)radianssincosisclose)AnyTYPE_CHECKING)Iterable)	BRep_Tool)BRepAlgoAPI_Cut)BRepBuilderAPI_MakeFace)BRepLib_FindSurface)BRepOffsetAPI_ThruSections)BRepPrimAPI_MakePrism)ShapeFix_FaceShapeFix_Shape)TopAbs_ShapeEnum)TopExp_Explorer)TopTools_ListOfShape)TopoDSTopoDS_CompoundTopoDS_FaceTopoDS_ShapeTopoDS_ShellTopoDS_VertexTopoDS_EdgeTopoDS_Wire)	TOLERANCEBoundBoxVector
VectorLike   )Shape	ShapeListdowncast	shapetype!_make_topods_compound_from_shapes)Vertex)EdgeWirec                <   t        |      }| %t        | t        t        t        t
        t        f      st        dt        |              t        | |j                        }t        |j                               }|j                         }|t        j                  k(  rg }t!        |t        j"                        }|j%                         rI|j'                  t        |j)                                      |j+                          |j%                         rIt-        |      }|S )a  extrude

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

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

    Raises:
        ValueError: Unsupported class
        RuntimeError: Generated invalid result

    Returns:
        TopoDS_Shape: extruded shape
    zextrude not supported for )r    
isinstancer   r   r   r   r   
ValueErrortyper   wrappedr%   r#   	ShapeTyper   TopAbs_COMPSOLIDr   TopAbs_SOLIDMoreappendCurrentNextr'   )obj	directionprism_builder	extrusion
shape_typesolidsexplorers          Q/opt/ringagent/.cad-venv/lib/python3.12/site-packages/build123d/topology/utils.py_extrude_topods_shaper?   _   s    ( y!I
{*	[+|L 5d3i[ABB)#y/@/@AM,,./I$$&J%666"9.>.K.KLmmoMM(8#3#3#567MMO mmo 6f=	    c                v   t        |       } t        |       dk  rt        d      | D cg c]  }t        |j                  t
              s|! }}t        |      }|dkD  rt        d      |dk(  rEt        | d   j                  t
              s(t        | d   j                  t
              st        d      |dk(  r^t        |       dk(  rt        d      t        | d   j                  t
              rt        | d   j                  t
              st        d	      t        ||      }| D ]n  }t        |j                  t
              r|j                  |j                         9t        |j                  t              sT|j                  |j                         p |j                          |j                         S c c}w )
a  make loft

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

    Args:
        wires (list[Wire]): section perimeters
        ruled (bool, optional): stepped or smooth. Defaults to False (smooth).

    Raises:
        ValueError: Too few wires

    Returns:
        TopoDS_Shape: Lofted object
       zMore than one wire is requiredzOnly two vertices are allowedr"   r   z=The vertex must be either at the beginning or end of the listz=You can't have only 2 vertices to loft; try adding some wiresz9The vertices must be at the beginning and end of the list)listlenr-   r,   r/   r   r   	AddVertexr   AddWireBuildr#   )objsfilledruledr7   verticesvertex_countloft_builders          r>   
_make_loftrO      s}   * :D
4y1}9::#Nz#++}'MNHNx=La899q47??M2d2h&&6K
 	
 qt9>O  tAw648++];K  .fe<L .ckk=1""3;;/[1  -	. K Os   F6	F6Nc                   |r t        j                  |       st        d      |rt        |      ng }t	        | g|z         }t        |d      j                         st        d      t        |       }|j                          t        j                  |j                               }t        |d      }|D ]q  }t        j                  |      st        d      t        |      }|j                          t        j                  |j                               }|j                  |       s |j                          |j                         st        d|j!                                |j#                         }t%        |      }	|	j'                          |	j                          t        j"                  |	j)                               S )a  _make_topods_face_from_wires

    Makes a planar face from one or more wires

    Args:
        outer_wire (TopoDS_Wire): closed perimeter wire
        inner_wires (Iterable[TopoDS_Wire], optional): holes. Defaults to None.

    Raises:
        ValueError: outer wire not closed
        ValueError: wires not planar
        ValueError: inner wire not closed
        ValueError: internal error

    Returns:
        TopoDS_Face: planar face potentially with holes
    z.Cannot build face(s): outer wire is not closedT)	OnlyPlanez&Cannot build face(s): wires not planarz.Cannot build face(s): inner wire is not closedzCannot build face(s): )r   
IsClosed_sr-   rD   r'   r   Foundr   Performr   r*   r#   r   AddrH   IsDoneErrorFacer   FixOrientationResult)

outer_wireinner_wiresverification_compoundsf_s	topo_wireface_builder
inner_wirefixed_inner_wirefacesf_fs
             r>   _make_topods_face_from_wiresre      su   ( 9//
;IJJ'2${#K >	{" 4EKKMABB *%DLLNDJJL)I*9d;L! +
##J/MNNj)!;;tzz|4)*+  1,2D2D2F1GHIIDDLLN;;t{{}%%r@   c                l   t        |       } t        |      }| D ch c]  }|j                   }}|D ch c]  }|j                   }}t        ||z
        }g }| |fD ]'  }|j                  t        |t               r|ng |       ) |D cg c]  }|j                  |v s| }}|S c c}w c c}w c c}w )z@Compare the OCCT objects of each list and return the differences)rD   r/   extendr,   )	
shapes_one
shapes_twoshapeocct_oneocct_two
occt_delta
all_shapesshapesshape_deltas	            r>   deltarq     s    j!Jj!J+56%6H6+56%6H6h)*JJz* MJvt$<&)F)LM&0PUEMMZ4O5PKP 76 Qs   B'B,B1B1c                    t        | t              r| n| g} t        | D cg c]  }|j                   c}      }t	        j
                  |t        d      }|j                  S c c}w )z2Return the maximum dimension of one or more shapesT)	toleranceoptimal)r,   r
   r'   r/   r   from_topo_dsr   diagonal)ro   s	compositebboxs       r>   find_max_dimensionrz     sQ    !&(3V&F1f2M1992MNI  iND== 3Ns   A!c                     t        | |||      S )a  Determine whether two floating point numbers are close in value.
    Overridden abs_tol default for the math.isclose function.

    Args:
        x (float): First value to compare
        y (float): Second value to compare
        rel_tol (float, optional): Maximum difference for being considered "close",
            relative to the magnitude of the input values. Defaults to 1e-9.
        abs_tol (float, optional): Maximum difference for being considered "close",
            regardless of the magnitude of the input values. Defaults to 1e-14
            (unlike math.isclose which defaults to zero).

    Returns: True if a is close in value to b, and False otherwise.
    )rel_tolabs_tol)r   )xyr|   r}   s       r>   	isclose_br     s     1a'::r@   c                R   t               }| j                         D ]*  }|j                  |j                  |j                         , t               }|D cg c]  }|j                         D ]  }|  c}}D ]*  }|j                  |j                  |j                         , t	               }|j                  |       |j                  |       |j                  d       |j                          g }t        |j                         t        j                        }	|	j                         rk| j                  j                  t!        |	j#                                     }
| |
_        |j'                  |
       |	j)                          |	j                         rkt+        |      S c c}}w )a  new_edges

    Given a sequence of shapes and the combination of those shapes, find the newly added edges

    Args:
        objects (Shape): sequence of shapes
        combined (Shape): result of the combination of objects

    Returns:
        ShapeList[Edge]: new edges
    T)r   edgesr/   Appendr   SetArgumentsSetToolsSetRunParallelrH   r   r#   r   TopAbs_EDGEr3   	__class__castr%   r5   topo_parentr4   r6   r$   )combinedobjectscombined_topo_edgesedgeoriginal_topo_edgesr7   e	operationr   r=   
found_edges              r>   	new_edgesr   -  sX    /0  5<<#&&t||45
 /0%;ssyy{;!;; 5<<#&&t||45
  !I./*+T"OOEy02B2N2NOH
--/'',,Xh6F6F6H-IJ
!)
Z 	 --/ U' <s   F#c                ^    | t        t        |            z  | t        t        |            z  fS )z4Convert polar coordinates into cartesian coordinates)r   r   r   )lengthangles     r>   polarr   W  s)    S((&3wu~3F*FGGr@   c                v    | d}|S t        | t        t        f      rt        |       }|S t        | g|z        }|S )zCreate a size tupleN)r,   tuplerD   )r7   dimresults      r>   tuplifyr   \  sJ    
{
 M	 
C%	's M us{#Mr@   c                    t        | j                  t              rY| D ch c]  }t        |j                         }}t	        |      dk(  r|j                         }|S t        | j                        }|S t        | j                        }|S c c}w )zReturn Shape's TopAbs_ShapeEnumr"   )r,   r/   r   r&   rE   pop)r7   o
shapetypesr   s       r>   unwrapped_shapetyper   g  s|    #++/478qi		*8
8z?a^^%F
 M s{{+F M 3;;'M 9s   B)r7   r   r8   r!   returnr   )F)rI   zIterable[Vertex | Wire]rJ   boolrK   r   r   r   )N)r[   r   r\   zIterable[TopoDS_Wire] | Noner   r   )rh   Iterable[Shape]ri   r   r   zlist[Shape])ro   zShape | Iterable[Shape]r   float)g&.>g+=)r~   r   r   r   r   r   )r   r#   r   r#   r   zShapeList[Edge])r   r   r   r   r   ztuple[float, float])r7   r   r   intr   ztuple | None)r7   r#   r   r   )E__doc__
__future__r   mathr   r   r   r   typingr   r	   collections.abcr
   OCP.BRepr   OCP.BRepAlgoAPIr   OCP.BRepBuilderAPIr   OCP.BRepLibr   OCP.BRepOffsetAPIr   OCP.BRepPrimAPIr   OCP.ShapeFixr   r   
OCP.TopAbsr   
OCP.TopExpr   OCP.TopToolsr   
OCP.TopoDSr   r   r   r   r   r   r   r   build123d.geometryr   r   r    r!   
shape_corer#   r$   r%   r&   r'   zero_dr(   one_dr)   r*   r?   rO   re   rq   rz   r   r   r   r   r    r@   r>   <module>r      s   2h # + + % $  + 6 + 8 1 6 ' & -	 	 	 G F  !&X = 
!= =  =  	= B JN9&9&*F9&9&x;$'TH

r@   