
    OgUi                    @   d dl mZ d dlmZmZmZmZ d dlmZ d dl	Z	d dl
Zd dlmZmZmZmZmZmZmZ g dZe	j*                  dz  Zd*d+d	Z	 d,	 	 	 	 	 d-dZ	 d.	 	 	 d/dZd0dZd1dZd2dZd3dZ	 	 d4	 	 	 	 	 	 	 	 	 d5dZ	 	 	 d6	 	 	 	 	 	 	 d7dZdZ  G d de      Z! G d d      Z"d
e d	 	 	 	 	 d8dZ#d
d
e d	 	 	 	 	 	 	 d9dZ$d
e d	 	 	 	 	 	 	 d:dZ%	 	 	 	 	 	 	 	 	 	 d;dZ& G d d      Z'd<d Z(d=d!Z)d>d"Z*d?d#Z+efd@d$Z,d1d%Z-e d&	 	 	 	 	 dAd'Z.e d&	 	 	 	 	 dBd(Z/dCd)Z0y)D    )annotations)SequenceIterableOptionalIterator)IntEnumN)Vec3Vec2Matrix44X_AXISY_AXISZ_AXISUVec)is_planar_facesubdivide_facesubdivide_ngonsPlanePlaneLocationStatenormal_vector_3psafe_normal_vectordistance_point_line_3dintersection_line_line_3dintersection_ray_polygon_3dintersection_line_polygon_3dbasic_transformationbest_fit_normalBarycentricCoordinateslinear_vertex_spacinghas_matrix_3d_stretchingspherical_envelopeinscribe_circle_tangent_lengthbending_anglesplit_polygon_by_plane is_face_normal_pointing_outwardsis_vertex_order_ccw_3d       @&.>c                8   t        |       dk  ryt        |       dk(  ryd}t        t        |       dz
        D ]N  }| ||dz    \  }}}	 ||z
  j                  ||z
        j                         }||}:|j                  ||      rN y |yy# t        $ r Y `w xY w)zReturns ``True`` if sequence of vectors is a planar face.

    Args:
         face: sequence of :class:`~ezdxf.math.Vec3` objects
         abs_tol: tolerance for normals check

       FTN   abs_tol)lenrangecross	normalizeZeroDivisionErrorisclose)facer,   first_normalindexabcnormals           [/var/www/html/public_html/myphp/venv/lib/python3.12/site-packages/ezdxf/math/construct3d.pyr   r   /   s     4y1}
4yA~Ls4y1}% 	uuqy)1a	!e]]1q5)335F !L%%fg%>	  ! 		s   %B	BBTc              #  p  K   t        |       dk  rt        d      t        |       }t        j                  |       |z  }t	        |      D cg c]  }| |   j                  | |dz   |z           ! }}t        |       D ]0  \  }}|r|||   |||dz
     f ||dz
     ||f |||   |f 2 yc c}w w)zSubdivides faces by subdividing edges and adding a center vertex.

    Args:
        face: a sequence of :class:`Vec3`
        quads: create quad faces if ``True`` else create triangles

    r)   z3 or more vertices required.   N)r-   
ValueErrorr	   sumr.   lerp	enumerate)r3   quadslen_facemid_posisubdiv_locationr5   vertexs           r:   r   r   K   s      4y1}788IHhhtnx'G8=h#34QT1q5H,-.#O # #4 :v/%0'?5ST9;UUU!%!),fg==/%0'99:	#s   A
B6$B10AB6c              #     K   | D ]i  }t        |      |k  rt        j                  |       )t        j                  |      t        |      z  }t	        |      D ]  \  }}||dz
     ||f  k yw)zSubdivides faces into triangles by adding a center vertex.

    Args:
        faces: iterable of faces as sequence of :class:`Vec3`
        max_vertex_count: subdivide only ngons with more vertices

    r<   N)r-   r	   tupler>   r@   )facesmax_vertex_countr3   rC   r5   rF   s         r:   r   r   f   su       7t9((**T""hhtns4y0G!*4 7v519ovw6677s   A0A2c                L    || z
  j                  || z
        j                         S )zlReturns normal vector for 3 points, which is the normalized cross
    product for: :code:`a->b x a->c`.
    )r/   r0   )r6   r7   r8   s      r:   r   r   z   s$     E==Q))++    c                    t        |       dk  rt        d      | ^}}}}	 ||z
  j                  ||z
        j                         S # t        $ r t        |       cY S w xY w)zjSafe function to detect the normal vector for a face or polygon defined
    by 3 or more `vertices`.

    r)   3 or more vertices required)r-   r=   r/   r0   r1   r   )verticesr6   r7   r8   _s        r:   r   r      sh    
 8}q677KAq!a)A}}QU#--// )x(()s   $A AAc                   t        j                  |       }t        |      dk  rt        d      |d   }|j	                  |d         s|j                  |       |j                  \  }}}d}d}d}|dd D ]B  }	|	j                  \  }
}}|||z   ||z
  z  z  }|||
z   ||z
  z  z  }|||z   ||
z
  z  z  }|
}|}|}D t        |||      j                         S )zReturns the "best fit" normal for a plane defined by three or more
    vertices. This function tolerates imperfect plane vertices. Safe function
    to detect the extrusion vector of flat arbitrary polygons.

    r)   rN   r           r<   N)r	   listr-   r=   r2   appendxyzr0   )rO   	_verticesfirstprev_xprev_yprev_znxnynzvxyzs                r:   r   r      s    		(#I
9~677aLE==2'"YYFFF	B	B	Bqr] %%1a
vzfqj))
vzfqj))
vzfqj)) B%%''rL   c                    |j                  |      rt        d      | |z
  }||z
  j                  |      }|j                  |j                  z
  }|dk  ryt	        j
                  |      S )zReturns the normal distance from a `point` to a 3D line.

    Args:
        point: point to test
        start: start point of the 3D line
        end: end point of the 3D line

    zNot a line.rS   )r2   r1   projectmagnitude_squaremathsqrt)pointstartendv1v2diffs         r:   r   r      sh     }}S..	B
+		r	"B!4!44Ds{ yyrL   c                    ddl m}m}  || ||      }t        |      dk7  ry|d   }|r|S  ||       j	                  |      r ||      j	                  |      r|S y)a  
    Returns the intersection point of two 3D lines, returns ``None`` if lines
    do not intersect.

    Args:
        line1: first line as tuple of two points as :class:`Vec3` objects
        line2: second line as tuple of two points as :class:`Vec3` objects
        virtual: ``True`` returns any intersection point, ``False`` returns only
            real intersection points
        abs_tol: absolute tolerance for comparisons

    r   )intersection_ray_ray_3dBoundingBoxr<   N)
ezdxf.mathro   rp   r-   inside)line1line2virtualr,   ro   rp   resrh   s           r:   r   r      sb    $ @
!%
8C
3x1}FE5  'K,>,E,Ee,LrL   c                $   t        |      \  }}}t        j                  |||      }|r|t        j                  |      z  }t        |       }|j                  s8|t        j
                  |j                  |j                  |j                        z  }|S )a  Returns a combined transformation matrix for translation, scaling and
    rotation about the z-axis.

    Args:
        move: translation vector
        scale: x-, y- and z-axis scaling as float triplet, e.g. (2, 2, 1)
        z_rotation: rotation angle about the z-axis in radians

    )	r	   r   scalez_rotateis_null	translater`   ra   rb   )moverx   
z_rotationsxsyszmr{   s           r:   r   r      sy     eJBBr2r"A	Xz**T
I	X	Y[[)++FFHrL   c                      e Zd ZdZdZdZdZy)r   r   r<   r*   r)   N)__name__
__module____qualname__COPLANARFRONTBACKSPANNING rL   r:   r   r      s    HEDHrL   r   c                      e Zd ZdZdZddZedd       Zedd       Zedd       Z	e
dd       Ze
dd       Zdd	ZeZd
 ZddZddZddZdddZdd dZded	 	 	 	 	 d!dZd"dZef	 	 	 d#dZy)$r   zConstruction tool for 3D planes.

    Represents a plane in 3D space as a normal vector and the perpendicular
    distance from the origin.
    _normal_distance_from_originc                J    |j                   du sJ d       || _        || _        y )NFzinvalid plane normal)rz   r   r   )selfr9   distances      r:   __init__zPlane.__init__  s)    ~~&>(>>&%-"rL   c                    | j                   S )zNormal vector of the plane.)r   r   s    r:   r9   zPlane.normal  s     ||rL   c                    | j                   S )z@The (perpendicular) distance of the plane from origin (0, 0, 0).)r   r   s    r:   distance_from_originzPlane.distance_from_origin  s     )))rL   c                4    | j                   | j                  z  S )zReturns the location vector.r   r   s    r:   vectorzPlane.vector  s     ||d8888rL   c                    	 ||z
  j                  ||z
        j                         }t	        ||j                  |            S # t        $ r t        d      w xY w)z+Returns a new plane from 3 points in space.z"undefined plane: colinear vertices)r/   r0   r1   r=   r   dot)clsr6   r7   r8   ns        r:   from_3pzPlane.from_3p#  s]    	CQa!e$..0A Qa!! ! 	CABB	Cs   %A Ac                    t        |      }	 t        |j                         |j                        S # t        $ r t        d      w xY w)z3Returns a new plane from the given location vector.zinvalid NULL vector)r	   r   r0   	magnituder1   r=   )r   r   r_   s      r:   from_vectorzPlane.from_vector,  sD     L	444  	4233	4s	   #1 Ac                N    | j                  | j                  | j                        S )zReturns a copy of the plane.)	__class__r   r   r   s    r:   __copy__zPlane.__copy__5  s    ~~dllD,F,FGGrL   c                N    dt        | j                         d| j                   dS )NzPlane(z, ))reprr   r   r   s    r:   __repr__zPlane.__repr__;  s(    T\\*+2d.H.H-IKKrL   c                `    t        |t              st        S | j                  |j                  k(  S N)
isinstancer   NotImplementedr   )r   others     r:   __eq__zPlane.__eq__>  s%    %'!!{{ell**rL   c                R    | j                   j                  |      | j                  z
  S )a  Returns signed distance of vertex `v` to plane, if distance is > 0,
        `v` is in 'front' of plane, in direction of the normal vector, if
        distance is < 0, `v` is at the 'back' of the plane, in the opposite
        direction of the normal vector.

        )r   r   r   r   r_   s     r:   signed_distance_tozPlane.signed_distance_toC  s$     ||"T%?%???rL   c                J    t        j                  | j                  |            S )z<Returns absolute (unsigned) distance of vertex `v` to plane.)rf   fabsr   r   s     r:   distance_tozPlane.distance_toL  s    yy00344rL   c                *    | j                  |      |k  S )zdReturns ``True`` if vertex `v` is coplanar, distance from plane to
        vertex `v` is 0.
        )r   )r   r_   r,   s      r:   is_coplanar_vertexzPlane.is_coplanar_vertexP  s     "W,,rL   c                    | j                   j                  } ||j                   |      xs  ||j                    |      S )ziReturns ``True`` if plane `p` is coplanar, normal vectors in same or
        opposite direction.
        r+   )r   r2   )r   pr,   
n_is_closes       r:   is_coplanar_planezPlane.is_coplanar_planeV  s=     \\))
!))W5 
YYJ:
 	
rL   Tcoplanarr,   c               D   | j                  ||      }| j                  ||      }||u ry|s%|t        j                  u s|t        j                  u ry| j                  }| j                  |j                  |      z
  |j                  ||z
        z  }|j                  ||      S )a  Returns the intersection point of the 3D line from `start` to `end`
        and this plane or ``None`` if there is no intersection. If the argument
        `coplanar` is ``False`` the start- or end point of the line are ignored
        as intersection points.

        N)vertex_location_stater   r   r9   r   r   r?   )	r   ri   rj   r   r,   state0state1r   weights	            r:   intersect_linezPlane.intersect_line_  s     ++E7;++C9V(111+444KK++aeeEl:aeeC%K>PPzz#v&&rL   c                    | j                   }	 | j                  |j                  |      z
  |j                  |      z  }|||z  z   S # t        $ r Y yw xY w)zReturns the intersection point of the infinite 3D ray defined by
        `origin` and the `direction` vector and this plane or ``None`` if there
        is no intersection. A coplanar ray does not intersect the plane!

        N)r9   r   r   r1   )r   origin	directionr   r   s        r:   intersect_rayzPlane.intersect_rayu  s^     KK	//!%%-?155CSSF V+,, ! 		s   0A 	AAc                    | j                   j                  |      | j                  z
  }|| k  rt        j                  S ||kD  rt        j
                  S t        j                  S )zjReturns the :class:`PlaneLocationState` of the given `vertex` in
        relative to this plane.

        )r   r   r   r   r   r   r   )r   rF   r,   r   s       r:   r   zPlane.vertex_location_state  sY     <<##F+d.H.HHwh%***%+++%...rL   N)r9   r	   r   float)returnr	   r   r   )r6   r	   r7   r	   r8   r	   r   'Plane')r   r   r   r   )r   r   )r   objectr   bool)r_   r	   r   r   r'   )r_   r	   r   r   )r   r   r   r   )ri   r	   rj   r	   r   Optional[Vec3])r   r	   r   r	   r   r   )rF   r	   r   r   )r   r   r   __doc__	__slots__r   propertyr9   r   r   classmethodr   r   r   copyr   r   r   r   r   r   PLANE_EPSILONr   r   r   r   rL   r:   r   r     s     5I.   * * 9 9 " " 4 4H DL+
@5-
 37'' $'	',- %2//	/rL   r   r   c               "   t         j                  }g }g }g }t        |       }|j                  }	|j                  }
|D ]*  }|j                  ||      }||z  }|j                  |       , |t         j                  k(  r*|r|t        |      }|
j                  |      dkD  r|}nY|}nU|t         j                  k(  r|}n>|t         j                  k(  r|}n'|t         j                  k(  rt        |      }t        |      D ]  }|dz   |z  }||   }||   }||   }||   }|t         j                  k7  r|j                  |       |t         j                  k7  r|j                  |       ||z  t         j                  k(  s~|	|
j                  |      z
  |
j                  ||z
        z  }|j                  ||      }|j                  |       |j                  |        t        |      dk  rg }t        |      dk  rg }t        |      t        |      fS )a7  Split a convex `polygon` by the given `plane`.

    Returns a tuple of front- and back vertices (front, back).
    Returns also coplanar polygons if the
    argument `coplanar` is ``True``, the coplanar vertices goes into either
    front or back depending on their orientation with respect to this plane.

    r   r<   r)   )r   r   rT   r   r9   r   rU   r   r   r   r   r   r-   r.   r?   rH   )polygonplaner   r,   polygon_typevertex_typesfront_verticesback_verticesrO   wr9   rF   vertex_typepolygon_normallen_verticesr5   
next_indexnext_vertex_typenext_vertexinterpolation_weightplane_intersection_points                        r:   r#   r#     s'    &..L-/L!#N "MG}H""A\\F  )11&'B#K() )222,X6Nzz.)A-!) (	+11	1!	+00	0 	+44	48}<( 	?E!)|3J&u-K+J7e_F":.K0555%%f-0666$$V,..3E3N3NN()FJJv,>(>&**&(C ($ ,2;;!5,( %%&>?$$%=>%	?& ~"N}!M %"666rL   )r   boundaryr,   c               
   t        |      }t        |      dk  rt        d      	 t        |      }t        ||j                  |d               }|j                  | |||      }	|	yt        |	||||      S # t        $ r Y yw xY w)a  Returns the intersection point of the 3D line form `start` to `end` and
    the given `polygon`.

    Args:
        start: start point of 3D line as :class:`Vec3`
        end: end point of 3D line as :class:`Vec3`
        polygon: 3D polygon as iterable of :class:`Vec3`
        coplanar: if ``True`` a coplanar start- or end point as intersection
            point is valid
        boundary: if ``True`` an intersection point at the polygon boundary line
            is valid
        abs_tol: absolute tolerance for comparisons

    r)   rN   Nr   r   )	rT   r-   r=   r   r1   r   r   r   (_is_intersection_point_inside_3d_polygon)
ri   rj   r   r   r   r,   rO   r9   r   ips
             r:   r   r     s    . G}H
8}q677#H- &&**Xa[12E			eS8W		MB	z3
Hfh   s   A6 6	BBr   r,   c                  t        |      }t        |      dk  rt        d      	 t        |      }t        ||j                  |d               }|j                  | |      }|yt        |||||      S # t        $ r Y yw xY w)a  Returns the intersection point of the infinite 3D ray defined by `origin`
    and the `direction` vector and the given `polygon`.

    Args:
        origin: origin point of the 3D ray as :class:`Vec3`
        direction: direction vector of the 3D ray as :class:`Vec3`
        polygon: 3D polygon as iterable of :class:`Vec3`
        boundary: if ``True`` intersection points at the polygon boundary line
            are valid
        abs_tol: absolute tolerance for comparisons

    r)   rN   Nr   )	rT   r-   r=   r   r1   r   r   r   r   )	r   r   r   r   r,   rO   r9   r   r   s	            r:   r   r     s    * G}H
8}q677#H- &&**Xa[12E			VY	/B	z3
Hfh   s   A3 3	A?>A?c                    ddl m}m}  ||      }t        j                  |j                  |            } |t        |j                  |             ||      }	|	dkD  s|r|	dk(  r| S y )Nr   )is_point_in_polygon_2dOCSr+   )rq   r   r   r
   rT   points_from_wcsfrom_wcs)
r   rO   r9   r   r,   r   r   ocsocs_verticesstates
             r:   r   r   $  sa     7
f+C99S00:;L"S\\"gE qyX%1*	rL   c                  (    e Zd ZdZddZddZddZy)	r   ah  Barycentric coordinate calculation.

    The arguments `a`, `b` and `c` are the cartesian coordinates of an arbitrary
    triangle in 3D space. The barycentric coordinates (b1, b2, b3) define the
    linear combination of `a`, `b` and `c` to represent the point `p`::

        p = a * b1 + b * b2 + c * b3

    This implementation returns the barycentric coordinates of the normal
    projection of `p` onto the plane defined by (a, b, c).

    These barycentric coordinates have some useful properties:

    - if all barycentric coordinates (b1, b2, b3) are in the range [0, 1], then
      the point `p` is inside the triangle (a, b, c)
    - if one of the coordinates is negative, the point `p` is outside the
      triangle
    - the sum of b1, b2 and b3 is always 1
    - the center of "mass" has the barycentric coordinates (1/3, 1/3, 1/3) =
      (a + b + c)/3

    c                   t        |      | _        t        |      | _        t        |      | _        | j                  | j                  z
  | _        | j                  | j                  z
  | _        | j                  | j                  z
  | _        | j                  j                  | j
                        }|j                         | _	        |j                  | j                        | _        t        | j                        dk  rt        d      y )Nr'   zinvalid triangle)r	   r6   r7   r8   _e1_e2_e3r/   r0   _nr   _denomabsr=   )r   r6   r7   r8   e1xe2s        r:   r   zBarycentricCoordinates.__init__M  s    aaa66DFF?66DFF?66DFF?txx(//#ii(t{{d"/00 #rL   c                   t        |      }| j                  }| j                  }|| j                  z
  }|| j                  z
  }|| j
                  z
  }| j                  j                  |      j                  |      |z  }| j                  j                  |      j                  |      |z  }| j                  j                  |      j                  |      |z  }	t        |||	      S r   )r	   r   r   r6   r7   r8   r   r/   r   r   r   )
r   r   r   denomd1d2d3b1b2b3s
             r:   from_cartesianz%BarycentricCoordinates.from_cartesianZ  s    GGGZZZXX^^B##A&.XX^^B##A&.XX^^B##A&.BBrL   c                    t        |      j                  \  }}}| j                  |z  | j                  |z  z   | j                  |z  z   S r   )r	   rV   r6   r7   r8   )r   r7   r  r  r  s        r:   to_cartesianz#BarycentricCoordinates.to_cartesianf  s=    !W[[
Bvv{TVVb[(466B;66rL   N)r6   r   r7   r   r8   r   )r   r   r   r	   )r7   r   r   r	   )r   r   r   r   r   r  r  r   rL   r:   r   r   3  s    21
 7rL   r   c                   |dk  r| |gS || z
  }|j                   r| g|z  S | g}|j                  |j                  |dz
  z        }t        d|dz
        D ]  }| |z  } |j	                  |         |j	                  |       |S )z=Returns `count` evenly spaced vertices from `start` to `end`.r*   r<   )rz   r0   r   r.   rU   )ri   rj   countr   rO   steprP   s          r:   r   r   k  s    zs|U{HwwHh00EAI>?D1eai   OOCOrL   c                   | j                  t              j                  }| j                  t              }| j                  t              }t        j                  ||j                         xs! t        j                  ||j                         S )a4  Returns ``True`` if matrix `m` performs a non-uniform xyz-scaling.
    Uniform scaling is not stretching in this context.

    Does not check if the target system is a cartesian coordinate system, use the
    :class:`~ezdxf.math.Matrix44` property :attr:`~ezdxf.math.Matrix44.is_cartesian`
    for that.
    )transform_directionr   re   r   r   rf   r2   )r   
ux_mag_sqruyuzs       r:   r   r   |  sx     &&v.??J	
		v	&B	
		v	&B||J(;(;<< DLLB''E A rL   c                v    t        j                  |       t        |       z  t        fd| D              }|fS )zCalculate the spherical envelope for the given points.  Returns the
    centroid (a.k.a. geometric center) and the radius of the enclosing sphere.

    .. note::

        The result does not represent the minimal bounding sphere!

    c              3  @   K   | ]  }j                  |        y wr   )r   ).0r   centroids     r:   	<genexpr>z%spherical_envelope.<locals>.<genexpr>  s     6!""1%6s   )r	   r>   r-   max)pointsradiusr  s     @r:   r    r      s7     xx#f+-H6v66FVrL   c                    | j                  |      }t        |dz  z
  }t        j                  t	        |      t              ryt	        t        j
                  |      |z        S )a  Returns the tangent length of an inscribe-circle of the given `radius`.
    The direction `dir1` and `dir2` define two intersection tangents,
    The tangent length is the distance from the intersection point of the
    tangents to the touching point on the inscribe-circle.

    r&   rS   )angle_betweenPI2rf   r2   r   tan)dir1dir2r  alphabetas        r:   r!   r!     sO     t$E%#+D||CIs#txx~&''rL   c                    | j                  |      }| j                  |      }|j                  |      s|j                  r|S |j                  |       r| S t	        d      )zReturns the bending angle from `dir1` to `dir2` in radians.

    The normal vector is required to detect the bending orientation,
    an angle > 0 bends to the "left" an angle < 0 bends to the "right".

    zinvalid normal vector)r  r/   r2   rz   r=   )r  r  r9   anglenns        r:   r"   r"     sZ     t$E	D	B	zz&RZZ	VG	v
,
--rL   c                `    ddl m}  ||       }t        j                  t	        |            dz  S )z6Returns a vertex from the "inside" of  the given face.r   )mapbox_earcut_3dg      @)ezdxf.math.triangulationr#  r	   r>   next)rO   r#  its      r:   any_vertex_inside_facer'    s)     :	(	#B88DH##rL   r+   c               V  	 dfd	t        |      }t        |      }t        ||j                  |            	fd| D        }t	               }|D ]J  }t        |||d      }|j                  |      kD  s+|j                  |j                  d             L t        |      S )zReturns the count of intersections of the normal-vector of the given
    `face` with the `faces` in front of this `face`.

    A counter-clockwise vertex order is assumed!

    c                L    t        |       dk  ryt        fd| D              S )Nr)   Fc              3  F   K   | ]  }j                  |      kD    y wr   )r   )r  r_   r,   detector_planes     r:   r  zZfront_faces_intersect_face_normal.<locals>.is_face_in_front_of_detector.<locals>.<genexpr>  s!     Ta>44Q7'ATs   !)r-   any)rO   r,   r+  s    r:   is_face_in_front_of_detectorzGfront_faces_intersect_face_normal.<locals>.is_face_in_front_of_detector  s#    x=1T8TTTrL   c              3  4   K   | ]  } |      s|  y wr   r   )r  fr-  s     r:   r  z4front_faces_intersect_face_normal.<locals>.<genexpr>  s     G'CA'F1Gs   Tr      )rO   Sequence[Vec3]r   r   )
r   r'  r   r   setr   r   addroundr-   )
rI   r3   r,   face_normalr   front_facesintersection_pointsr   r+  r-  s
     `     @@r:   !front_faces_intersect_face_normalr8    s    U %T*K#D)F;(?@N HeGK
 &)U 	1(Kg
 :,,R07:  ##BHHQK0	1 "##rL   c               *    t        | ||      dz  dk(  S )aP  Returns ``True`` if the face-normal for the given `face` of a
    closed surface is pointing outwards. A counter-clockwise vertex order is
    assumed, for faces with clockwise vertex order the result is inverted,
    therefore ``False`` is pointing outwards.

    This function does not check if the `faces` are a closed surface.

    r+   r*   r   )r8  )rI   r3   r,   s      r:   r$   r$     s     -UD'JQNRSSSrL   c                ,    t               dk  rt        d      d fd}t        |j                        t        |j                        t        |j
                        f}|j                  t        |             |       dkD  }|   }|r|dkD  S |dk  S )a  Returns ``True`` when the given 3D vertices have a counter-clockwise order around
    the given normal vector.

    Works for convex and concave shapes. Does not check or care if all vertices are
    located in a flat plane or if the normal vector is really perpendicular to the
    shape, but the result may be incorrect in that cases.

    Args:
        vertices (list): corner vertices of a flat shape (polygon)
        normal (Vec3): normal vector of the shape

    Raises:
        ValueError: input has less than 3 vertices

    r)   rN   c                 \   t        j                        } dk(  r| d d df   | d d df   }}n*dk(  r| d d df   | d d df   }}n| d d df   | d d df   }}t        j                  |t        j                  |d            t        j                  |t        j                  |d            z
  S )Nr   r<   r*   rR   )nparrayr   roll)r   r`   ra   domrO   s      r:   signed_areaz+is_vertex_order_ccw_3d.<locals>.signed_area  s    ((8$!81a4='!Q$-qAAX1a4='!Q$-qA1a4='!Q$-qAvvaB(266!RWWQ^+DDDrL   r   r   )r-   r=   r   r`   ra   rb   r5   r  )rO   r9   r@  abs_axisccwdom_axisr?  s   `     @r:   r%   r%     s      8}q677
E 688}c&((mS]:H
..X
'C
-!
Cc{H8a<0HqL0rL   r   )r3   r1  r   r   )T)r3   r1  rA   r   r   Iterator[Sequence[Vec3]])   )rI   zIterable[Sequence[Vec3]]r   rD  )r6   r	   r7   r	   r8   r	   r   r	   )rO   r1  r   r	   )rO   zIterable[UVec]r   r	   )rh   r	   ri   r	   rj   r	   r   r   )Tg|=)
rs   r1  rt   r1  ru   r   r,   r   r   r   ))r   r   r   )r<   r<   r<   r   )r|   r   rx   r   r}   r   r   r   )r   Iterable[Vec3]r   r   r   z%tuple[Sequence[Vec3], Sequence[Vec3]])ri   r	   rj   r	   r   rF  r   r   )r   r	   r   r	   r   rF  r   r   )
r   r	   rO   
list[Vec3]r9   r	   r   r   r,   r   )ri   r	   rj   r	   r  intr   rG  )r   r   r   r   )r  zSequence[UVec]r   ztuple[Vec3, float])r  r	   r  r	   r  r   r   r   )r  r	   r  r	   r   r   )rI   Sequence[Sequence[Vec3]]r3   r1  r   rH  )rI   rI  r3   r1  r   r   )rO   rG  r9   r	   r   r   )1
__future__r   typingr   r   r   r   enumr   rf   numpyr<  rq   r	   r
   r   r   r   r   r   __all__pir  r   r   r   r   r   r   r   r   r   r   r   r   r#   r   r   r   r   r   r   r    r!   r"   r'  r8  r$   r%   r   rL   r:   <module>rP     se   # 9 9     0 ggm: )-:
:!%::: 7#7 7(,)(86 	  	
 B 
  	0  J/ J/b C7C7C7 +C7V $$	$ $ $X """ " "J",0<@KP57 57p" ( 28 . $ 	($#($
($
 	($^ 	T#T
T
 
T"'1rL   