
    h
                      S r SSKJr  SSKJrJrJrJrJrJ	r	J
r
  SSKrSSKrSSKJrJrJrJrJrJrJrJrJr  SSKJr  SSKJr  SS	KJr  \(       a  SS
KJrJrJrJ r   / SQr! S8     S9S jjr"S:S jr#   S;         S<S jjr$  S=       S>S jjr%S?S jr&S@SAS jjr'SAS jr(SBS jr)SCSDS jjr*SCSDS jjr+ SE       SFS jjr,SGS jr-SGS jr.SGS jr/SGS jr0SGS jr1SHS jr2 SI         SJS jjr3 SI             SKS jjr4    SLS  jr5          SMS! jr6      SNS" jr7 " S# S5      r8SOS$ jr9  SP       SQS% jjr:  SP       SQS& jjr;     SR           SSS' jjr<\Rz                  S(-  r> ST     SUS) jjr?STSVS* jjr@SWS+ jrA          SXS, jrB\
SYS- j5       rCSZS. jrD    S[S/ jrES0S1S2S3.     S\S4 jjrF " S5 S65      rGS]S7 jrHg)^aG  
B-Splines
=========

https://www.cl.cam.ac.uk/teaching/2000/AGraphHCI/SMEG/node4.html

Rational B-splines
==================

https://www.cl.cam.ac.uk/teaching/2000/AGraphHCI/SMEG/node5.html:

"The NURBS Book" by Les Piegl and Wayne Tiller

https://books.google.at/books/about/The_NURBS_Book.html?id=7dqY5dyAwWkC&redir_esc=y

    )annotations)IterableIteratorSequenceTYPE_CHECKINGOptionalAnyno_type_checkN)	Vec3UVecNULLVECBasis	Evaluatorcreate_t_vectorestimate_end_tangent_magnitudedistance_point_line_3darc_angle_span_deg   )BoundingBox)linalg)DXFValueError)ConstructionArcConstructionEllipseMatrix44Bezier4P)fit_points_to_cad_cvglobal_bspline_interpolation!local_cubic_bspline_interpolationrational_bspline_from_arcrational_bspline_from_ellipsefit_points_to_cubic_bezieropen_uniform_bsplineclosed_uniform_bsplineBSpline*unconstrained_global_bspline_interpolation)global_bspline_interpolation_end_tangentscad_fit_point_interpolation.global_bspline_interpolation_first_derivatives/local_cubic_bspline_interpolation_from_tangentsknots_from_parametrizationaveraged_knots_unconstrainedaveraged_knots_constrainednatural_knots_unconstrainednatural_knots_constraineddouble_knotsrequired_knot_valuesuniform_knot_vectoropen_uniform_knot_vectorrequired_fit_pointsrequired_control_pointsr$   c                F   [         R                  " U 5      n[        U5      S:  a  [        S5      eUc  [	        U5      u  p4[        USUS9$ [         R                  " U5      n[        USS9u  pgUS   R                  U5      nUS   R                  U5      n	[        US	X4SS
9$ )a}  Returns a cubic :class:`BSpline` from fit points as close as possible
to common CAD applications like BricsCAD.

There exist infinite numerical correct solution for this setup, but some
facts are known:

- CAD applications use the global curve interpolation with start- and end
  derivatives if the end tangents are defined otherwise the equation system will
  be completed by setting the second derivatives of the start and end point to 0,
  for more information read this answer on stackoverflow: https://stackoverflow.com/a/74863330/6162864
- The degree of the B-spline is always 3 regardless which degree is stored in the
  SPLINE entity, this is only valid for B-splines defined by fit points
- Knot parametrization method is "chord"
- Knot distribution is "natural"

Args:
    fit_points: points the spline is passing through
    tangents: start- and end tangent, default is autodetect

   two or more points required    orderknotschordmethodr      )degreetangentsr>   )	r   listlen
ValueErrorr'   r$   r   	normalizer   )

fit_pointsrB   pointscontrol_pointsr;   tm1m2start_tangentend_tangents
             D/var/www/html/env/lib/python3.13/site-packages/ezdxf/math/bspline.pyr   r   Z   s    2 YYz"F
6{Q788 ;F C~Qe<<		(A+F7CFBaDNN2&MB%//"%K'-	     c                    [         R                  " U 5      n[        U5      S:  a  [        S5      eSSKJnJn  U" U5      nU" U5      $ )u  Returns a cubic :class:`BSpline` from fit points **without** end
tangents.

This function uses the cubic Bèzier interpolation to create multiple Bèzier
curves and combine them into a single B-spline, this works for short simple
splines better than the :func:`fit_points_to_cad_cv`, but is worse
for longer and more complex splines.

Args:
    fit_points: points the spline is passing through

r6   r7   r   )cubic_bezier_interpolationbezier_to_bspline)r   rC   rD   rE   
ezdxf.mathrR   rS   )rG   rH   rR   rS   bezier_curvess        rO   r!   r!      sA     YYz"F
6{Q788H.v6M]++rP   c                   [         R                  " U 5      n[        U5      nUS-   nU(       a  US-  nXe:  a  Uc  [        SU 35      e[        [	        XC5      5      nUS-  (       a  SOSnUbq  [         R                  " U5      n	[        U	5      S:X  a  [        UU	S   U	S   UUU5      u  pOA[        U	5      [        U5      :X  a  [        XIX5      u  n
nO[        S5      e[        XAXx5      u  p[        XUS9nU$ )	a$  `B-spline`_ interpolation by the `Global Curve Interpolation`_.
Given are the fit points and the degree of the B-spline.
The function provides 3 methods for generating the parameter vector t:

- "uniform": creates a uniform t vector, from 0 to 1 evenly spaced, see
  `uniform`_ method
- "chord", "distance": creates a t vector with values proportional to the
  fit point distances, see `chord length`_ method
- "centripetal", "sqrt_chord": creates a t vector with values proportional
  to the fit point sqrt(distances), see `centripetal`_ method
- "arc": creates a t vector with values proportional to the arc length
  between fit points.

It is possible to constraint the curve by tangents, by start- and end
tangent if only two tangents are given or by one tangent for each fit point.

If tangents are given, they represent 1st derivatives and should be
scaled if they are unit vectors, if only start- and end tangents given the
function :func:`~ezdxf.math.estimate_end_tangent_magnitude` helps with an
educated guess, if all tangents are given, scaling by chord length is a
reasonable choice (Piegl & Tiller).

Args:
    fit_points: fit points of B-spline, as list of :class:`Vec3` compatible
        objects
    tangents: if only two vectors are given, take the first and the last
        vector as start- and end tangent constraints or if for all fit
        points a tangent is given use all tangents as interpolation
        constraints (optional)
    degree: degree of B-spline
    method: calculation method for parameter vector t

Returns:
    :class:`BSpline`

r   r6   z$More fit points required for degree naturalaverager   zoInvalid count of tangents, two tangents as start- and end tangent constrains or one tangent for each fit point.r9   )	r   rC   rD   rE   r   r&   r(   r%   r$   )rG   rA   rB   r>   _fit_pointscountr:   t_vectorknot_generation_method	_tangentsrI   r;   bsplines                rO   r   r      s   T ))J'KE!E
})?xHIIOK89H*01*Y)IIh'	y>Q$M!!&%!NE ^s;// ?
 H 
 !K!
 n?GNrP   c                    SSK Jn  [        R                  " U 5      nU(       a  [        R                  " U5      nOU" XA5      n[	        XE5      u  pg[        USUS9$ )a  `B-spline`_ interpolation by 'Local Cubic Curve Interpolation', which
creates B-spline from fit points and estimated tangent direction at start-,
end- and passing points.

Source: Piegl & Tiller: "The NURBS Book" - chapter 9.3.4

Available tangent estimation methods:

- "3-points": 3 point interpolation
- "5-points": 5 point interpolation
- "bezier": cubic bezier curve interpolation
- "diff": finite difference

or pass pre-calculated tangents, which overrides tangent estimation.

Args:
    fit_points: all B-spline fit points as :class:`Vec3` compatible objects
    method: tangent estimation method
    tangents: tangents as :class:`Vec3` compatible objects (optional)

Returns:
    :class:`BSpline`

r   )estimate_tangentsr8   r9   )parametrizer`   r   rC   r)   r$   )rG   r>   rB   r`   rY   r]   rI   r;   s           rO   r   r      sQ    : /))J'KIIh'	%k:	KN >%88rP   c                    [        U5      n[        U 5      S-
  nUS-
  nSUs=::  a	  US-   ::  d  O  [        S5      eX4-   S-   $ )uR  Returns the count of required knot-values for a B-spline of `order` and
`count` control points.

Args:
    count: count of control points, in text-books referred as "n + 1"
    order: order of B-Spline, in text-books referred as "k"

Relationship:

"p" is the degree of the B-spline, text-book notation.

- k = p + 1
- 2 ≤ k ≤ n + 1

r   r6   zInvalid count/order combination)intr   )rZ   r:   knps        rO   r0   r0     sL      	E
AE
QA	AAq1u=>>519rP   c                2    U(       a  U S-  n [        U S5      $ )zReturns the count of required fit points to calculate the spline
control points.

Args:
    order: spline order (degree + 1)
    tangents: start- and end tangent are given or estimated

r6   max)r:   rB   s     rO   r3   r3   7  s      	
ua=rP   c                    [        U S5      $ )zReturns the required count of control points for a valid B-spline.

Args:
    order: spline order (degree + 1)

Required condition: 2 <= order <= count, therefore:  count >= order

r6   rh   )r:   s    rO   r4   r4   I  s     ua=rP   c                V    U S   nU S   U-
  nU  Vs/ s H
  o3U-
  U-  PM     sn$ s  snf )z(Normalize knot vector into range [0, 1].r   r?    )r;   min_valmax_valvs       rO   normalize_knotsrp   U  s8    AhGBi'!G-23U[G#U333s   &c                    U(       a  [        X-   S-
  5      nOSn[        X-   5       Vs/ s H  oDU-  PM	     sn$ s  snf )zReturns an uniform knot vector for a B-spline of `order` and `count`
control points.

`order` = degree + 1

Args:
    count: count of control points
    order: spline order
    normalize: normalize values in range [0, 1] if ``True``

r         ?)floatrange)rZ   r:   rF   	max_value
knot_values        rO   r1   r1   \  sA     %-!+,		5:5=5IJ5Iz"5IJJJs   ;c                   ^ X-
  nU(       a  [        X-
  S-   5      mS/U-  nOSmSU-   /U-  nS/U-  nUR                  U4S j[        U5       5       5        UR                  U5        U$ )zReturns an open (clamped) uniform knot vector for a B-spline of `order`
and `count` control points.

`order` = degree + 1

Args:
    count: count of control points
    order: spline order
    normalize: normalize values in range [0, 1] if ``True``

r   rr           c              3  4   >#    U  H  nS U-   T-  v   M     g7f)rr   Nrl   ).0ro   ru   s     rO   	<genexpr>+open_uniform_knot_vector.<locals>.<genexpr>  s     91#'Y&   )rs   extendrt   )rZ   r:   rF   rd   tailr;   ru   s         @rO   r2   r2   o  sr     	A%-!+,	uu}	ay5 EEME	LL9a99	LLLrP   c                   [        US-   5      nXPS-   :  a  [        S5      eU Vs/ s H  n[        U5      PM     nnUS   S:w  d  [        R                  " US   S5      (       d  [        S5      eUS:X  a  U(       a  [        XU5      $ [        XU5      $ US	:X  a  U(       a  [        XU5      $ [        XU5      $ [        S
U 35      es  snf )a  Returns a 'clamped' knot vector for B-splines. All knot values are
normalized in the range [0, 1].

Args:
    n: count fit points - 1
    p: degree of spline
    t: parametrization vector, length(t_vector) == n, normalized [0, 1]
    method: "average", "natural"
    constrained: ``True`` for B-spline constrained by end derivatives

Returns:
    List of n+p+2 knot values as floats

r   z2Invalid n/p combination, more fit points required.r   rx   r?   rr   z.Parametrization vector t has to be normalized.rX   rW   z Unknown knot generation method: )
rc   r   rs   mathiscloserE   r,   r+   r.   r-   )re   rf   rJ   r>   constrainedr:   ro   s          rO   r*   r*     s    " AJEAPQQ1aq1Ats{$,,quc22IJJ  'qQ/	
 .aA6	

 
9	  &aA.	
 -Q15	
 ;F8DEE# 	s   Cc                $  ^^ TS   S:X  d   e[         R                  " TS   S5      (       d   eS/TS-   -  nUR                  UU4S j[        SU T-
  S-   5       5       5        US   S:  a  [	        S5      eUR                  S/TS-   -  5        U$ )zReturns an averaged knot vector from parametrization vector `t` for an
unconstrained B-spline.

Args:
    n: count of control points - 1
    p: degree
    t: parametrization vector, normalized [0, 1]

r   rx   r?   rr   r   c              3  J   >#    U  H  n[        TXT-    5      T-  v   M     g 7fNsumrz   jrf   rJ   s     rO   r{   /averaged_knots_unconstrained.<locals>.<genexpr>  s%     D0C1Qqq5\"Q&0Cs    #z!Normalized [0, 1] values required)r   r   r~   rt   rE   re   rf   rJ   r;   s    `` rO   r+   r+     s     Q43;;<<"s####EQUOE	LLDaQ0CDDRy3<==	LL#!a%!LrP   c                   ^^ TS   S:X  d   e[         R                  " TS   S5      (       d   eS/TS-   -  nUR                  UU4S j[        U T-
  5       5       5        UR                  S/TS-   -  5        U$ )zReturns an averaged knot vector from parametrization vector `t` for a
constrained B-spline.

Args:
    n: count of control points - 1
    p: degree
    t: parametrization vector, normalized [0, 1]

r   rx   r?   rr   r   c              3  P   >#    U  H  n[        TXT-   S -
   5      T-  v   M     g7f)r   Nr   r   s     rO   r{   -averaged_knots_constrained.<locals>.<genexpr>  s(     ALqQqq519%&*Ls   #&)r   r   r~   rt   r   s    `` rO   r,   r,     st     Q43;;<<"s####EQUOE	LLAE!a%LAA	LL#!a%!LrP   c                    US   S:X  d   e[         R                  " US   S5      (       d   eS/US-   -  nUR                  USX-
  S-    5        UR                  S/US-   -  5        U$ )zReturns a 'natural' knot vector from parametrization vector `t` for an
unconstrained B-spline.

Args:
    n: count of control points - 1
    p: degree
    t: parametrization vector, normalized [0, 1]

r   rx   r?   rr   r   r6   r   r   r~   r   s       rO   r-   r-     r     Q43;;<<"s####EQUOE	LL1quqy!"	LL#!a%!LrP   c                    US   S:X  d   e[         R                  " US   S5      (       d   eS/US-   -  nUR                  USX-
  S-    5        UR                  S/US-   -  5        U$ )zReturns a 'natural' knot vector from parametrization vector `t` for a
constrained B-spline.

Args:
    n: count of control points - 1
    p: degree
    t: parametrization vector, normalized [0, 1]

r   rx   r?   rr   r   r   r   s       rO   r.   r.     r   rP   c                &   US   S:X  d   e[         R                  " US   S5      (       d   eS/US-   -  nSn/ nUSS  H  nUS:X  a(  UR                  XF-   S-  5        UR                  U5        OOUS:X  a  UR                  US-  5        O4UR                  SU-  U-   S-  5        UR                  USU-  -   S-  5        UnM     UR                  US	U S-  U-
   5        UR                  US
   S-   S-  5        UR                  S/US-   -  5        U$ )a  Returns a knot vector from parametrization vector `t` for B-spline
constrained by first derivatives at all fit points.

Args:
    n: count of fit points - 1
    p: degree of spline
    t: parametrization vector, first value has to be 0.0 and last value has
        to be 1.0

r   rx   r?   rr   r   r6          @      @N)r   r   appendr~   )re   rf   rJ   uprev_tu1t1s          rO   r/   r/      s    Q43;;<<"s####	QAF	B"g6IIv{c)*IIbM}		"q&! 		1v:?c12		6AF?c12  HHR!a%!)_HHaeckS !HHcUa!e_HrP   c                V   [        U [        R                  5      (       d  [        R                  " U 5      n U R                  S:  a   [        R                  " U R
                  5      $ [        R                  " U SS9u  p#[        R                  " XU5      n[        R                  " XBU5      $ )zeReturns best suited linear equation solver depending on matrix configuration and
python interpreter.
   F)	check_all)	
isinstancer   MatrixnrowsNumpySolvermatrixdetect_banded_matrixcompact_banded_matrixBandedMatrixLU)r   rA   rK   rL   As        rO   _get_best_solverr   &  s     ffmm,,v&||b!!&--00 ,,VuE((R8$$QB//rP   c                t   [        [        U 5      S-
  UUUSS9n[        XAS-   [        U 5      S9n[        U Vs/ s H  oeR	                  U5      PM     snU5      n[
        R                  " U [
        R                  S9nUR                  U5      n	[        R                  " U	R                  5       5      U4$ s  snf )a>  Interpolates the control points for a B-spline by global interpolation
from fit points without any constraints.

Source: Piegl & Tiller: "The NURBS Book" - chapter 9.2.1

Args:
    fit_points: points the B-spline has to pass
    degree: degree of spline >= 2
    t_vector: parametrization vector, first value has to be 0 and last
        value has to be 1
    knot_generation_method: knot generation method from parametrization
        vector, "average" or "natural"

Returns:
    2-tuple of control points as list of Vec3 objects and the knot vector
    as list of floats

r   Fr   r;   r:   rZ   dtype)r*   rD   r   r   basis_vectornparrayfloat64solve_matrixr   rC   rows)
rG   rA   r[   r\   r;   NrJ   solvermat_BrI   s
             rO   r%   r%   =  s    2 'J!E 	E!3z?CA(C(Q~~a0(CVLFHHZrzz2E((/N99^((*+U22 Ds   B5c                (   [        U 5      S-
  nUnUS:  a  Sn[        US-   XtUSS9n[        XS-   US-   S9n	U V
s/ s H  oR                  U
5      PM     nn
S/US-   -  nUR	                  SS	S
/U-   5        UR	                  SUS	S
/-   5        U R	                  SXUS-      U-  -  5        U R	                  SUS
XS-   *    -
  U-  -  5        [        X5      nUR                  U 5      n[        R                  " UR                  5       5      U4$ s  sn
f )ap  Calculates the control points for a B-spline by global interpolation
from fit points and the 1st derivative of the start- and end point as constraints.
These 'tangents' are 1st derivatives and not unit vectors, if an estimation
of the magnitudes is required use the :func:`estimate_end_tangent_magnitude`
function.

Source: Piegl & Tiller: "The NURBS Book" - chapter 9.2.2

Args:
    fit_points: points the B-spline has to pass
    start_tangent: 1st derivative as start constraint
    end_tangent: 1st derivative as end constrain
    degree: degree of spline >= 2
    t_vector: parametrization vector, first value has to be 0 and last
        value has to be 1
    knot_generation_method: knot generation method from parametrization
        vector, "average" or "natural"

Returns:
    2-tuple of control points as list of Vec3 objects and the knot vector
    as list of floats

r   r@   rW   r6   Tr   r   rx         rr   r?   )
rD   r*   r   r   insertr   r   r   rC   r   )rG   rM   rN   rA   r[   r\   re   rf   r;   r   r   r   spacingr   rI   s                  rO   r&   r&   d  s/   > 	J!AAz "+&	Aq2E 	EQa!e4A'/0x!NN1xD0eq1uoGKKD$<')*KKGtTl*+aA,*:;<b+#Ah*?1)DEFd+F((4N99^((*+U22 1s   Dc                l  ^^ SUU4S jjnSUU4S jjn[        [        U S5      5      n[        U 5      S-
  nSm[        US-   TUSSS	9m[	        TTS-   US-   S
9nU Vs/ s H  oeR                  U5      PM     nnS/U-  nUR                  SU" 5       U-   5        UR                  SX" 5       -   5        U R                  S[        SSS5      5        U R                  S[        SSS5      5        [        UT5      n	U	R                  U 5      n
[        R                   " U
R                  5       5      T4$ s  snf )an  Calculates the control points for a B-spline by global interpolation
from fit points without any constraints in the same way as AutoCAD and BricsCAD.

Source: https://stackoverflow.com/a/74863330/6162864

Args:
    fit_points: points the B-spline has to pass

Returns:
    2-tuple of control points as list of Vec3 objects and the knot vector
    as list of floats

c                 b   > TTS-      n TTS-      nTTS-
  -  U -  nX -  U* X-   -  X-  -  X!-  /$ )z*Returns the coefficients for equation [1].r   r6   rl   )up1up2fr;   rf   s      rO   coefficients12cad_fit_point_interpolation.<locals>.coefficients1  sX     AElAElQK#GB#)	*G
 	
rP   c                    > [        T5      S-
  n TU T-
  S-
     nTU T-
  S-
     nTTS-
  -  SU-
  -  nUSU-
  -  U* SU-
  U-
  -  SU-
  -  SU-
  -  USU-
  -  /$ )z,Returns the coefficients for equation [n-1].r   r6   rr   r   rD   )mump1ump2r   r;   rf   s       rO   coefficients22cad_fit_point_interpolation.<locals>.coefficients2  s     JNQUQYQUQYQK3:&tB#*t#$d
3sTzBt
 	
rP   r<   r   r@   r6   rW   T)r>   r   r   rx   r?   r   )returnlist[float])rC   r   rD   r*   r   r   r   r   r   r   r   )rG   r   r   r[   re   r   r   r   r   r   rI   r;   rf   s              @@rO   r'   r'     s.   "

 


 
 OJ89HJ!A	A&	Aq(9$E 	EQa!e4A'/0x!NN1xD0eaiGKK=?W,-KKGmo-. aaA'b$q!Q-(dA&F((4N99^((*+U22 1s   D1c           	     n  ^^^^ SUUU4S jjmUm[        U 5      S-
  n[        UTU5      n[        U 5      S-  m[        UTS-   TS9mS/S/TS-
  -  -   SS/S/TS-
  -  -   /n[        US   5      nU4S	 jUSS
  5        H'  nUR                  U V	s/ s H  oSU PM	     sn	5        M)     UR	                  S/TS-
  -  SS/-   5        UR	                  S/TS-
  -  S/-   5        [        [        S U 5       5      5      S:X  d   S5       e/ n
[        X5       H  nU
R                  U5        M     U
S   U
S
   sU
S
'   U
S'   U
S==   UTS-      T-  -  ss'   U
S==   SUTS-   *    -
  T-  -  ss'   [        Xb5      nUR                  U
5      n[        R                  " UR                  5       5      U4$ s  sn	f )ag  Interpolates the control points for a B-spline by a global
interpolation from fit points and 1st derivatives as constraints.

Source: Piegl & Tiller: "The NURBS Book" - chapter 9.2.4

Args:
    fit_points: points the B-spline has to pass
    derivatives: 1st derivatives as constrains, not unit vectors!
        Scaling by chord length is a reasonable choice (Piegl & Tiller).
    degree: degree of spline >= 2
    t_vector: parametrization vector, first value has to be 0 and last
        value has to be 1

Returns:
    2-tuple of control points as list of Vec3 objects and the knot vector
    as list of floats

c              3     >#    TR                  U 5      nUT-
  nTT-   S-   U-
  nTR                  XSS9 H  nS/U-  U-   S/U-  -   v   M     g 7f)Nr   re   rx   )	find_spanbasis_funcs_derivatives)rJ   spanfrontbackbasisr   rZ   rf   s        rO   nbasis>global_bspline_interpolation_first_derivatives.<locals>.nbasis  sd     {{1~qqy1}t#..t!.<E%%-%'3%$,66 =s   AAr   r6   r   rr   rx   r   r   c              3  4   >#    U  H  nT" U5      v   M     g 7fr   rl   )rz   rJ   r   s     rO   r{   Aglobal_bspline_interpolation_first_derivatives.<locals>.<genexpr>  s     0AfQiir}   r?   Nc              3  8   #    U  H  n[        U5      v   M     g 7fr   r   )rz   rows     rO   r{   r   
  s     )q3s88qs   zinhomogeneous matrix detectedr   )rJ   rs   )rD   r/   r   r~   r   setzipr   r   r   rC   r   )rG   derivativesrA   r[   re   r;   r   ncolsr   r   Br   r   rI   r   rZ   r   rf   s                 @@@@rO   r(   r(     s   27 7 	AJ!AAx(E
OaEEQe4A	##	tu	**	A !IE0!B0	+#fu++, 1 HHcUeai D$</0HHcUeai D6)*s)q))*a/P1PP/ AJ,	 - R5!B%LAbE1R5 aDE!a%L1DbEcEAE(O#q((Ea(F((+N99^((*+U22' ,s   F2
c                J   [        U 5      [        U5      :X  d   e[        U 5      S:  d   eSnUS-   nU S   /nSn/ n[        [        U 5      S-
  5       H  nX   nXS-      n	X   n
XS-      nSX-   R                  -
  nSX-
  R                  X-   5      -  nSX-
  R                  -  n [        R
                  " XU5      u  nnXU
-  S	-  -   nXU-  S	-  -
  nUR                  UU45        US	UU-
  R                  -  -  nUR                  U5        M     UR                  U S
   5        S/U-  nUS
   nUSS
  H  nUU-  nUR                  UU45        M     UR                  S/S-  5        [        U5      [        [        U5      U5      :X  d   eUU4$ ! [         a     GMM  f = f)a  Interpolates the control points for a cubic B-spline by local
interpolation from fit points and tangents as unit vectors for each fit
point. Use the :func:`estimate_tangents` function to estimate end tangents.

Source: Piegl & Tiller: "The NURBS Book" - chapter 9.3.4

Args:
    fit_points: curve definition points - curve has to pass all given fit
        points
    tangents: one tangent vector for each fit point as unit vectors

Returns:
    2-tuple of control points as list of Vec3 objects and the knot vector
    as list of floats

r6   r@   r   r   rx   g      0@g      (@g      Br   r?   Nrr   r8   )rD   rt   magnitude_squaredotr   quadratic_equationrE   r~   	magnituder   r0   )rG   rB   rA   r:   rI   r   paramsip0p3t0t3abc
alpha_plusalpha_minusp1p2r;   max_uro   knots                          rO   r)   r)     s   & z?c(m+++z?QFQJE m_NAF3z?Q&']A[!e_BG---BG==))RW...	&,&?&?a&H#J r/C''r/C''r2h'	SBG&&&&a! (" *R.)EEME2JECR[5ydD\"  
LL#u:-c..A5IIII5  #  		s   (F
F"!F"c                  l   \ rS rSrSrSr   S/       S0S jjrS r\S1S j5       r	\S2S j5       r
\S3S	 j5       r\S2S
 j5       r\S2S j5       r\S4S j5       r\S 5       r\S 5       r\S5S6S jj5       r\S7S8S jj5       r\S7S9S jj5       r\S:S j5       r\S;S j5       r\S<S j5       rS<S jrS=S jrS=S jrS>S?S jjrS@S jrSASBS jjrSCS jrSDS jrSESFS jjr SESGS jjr!SHS jr"SHS  jr#SIS! jr$SJS" jr%SKS# jr& SL     SMS$ jjr'SNSOS% jjr(SPS& jr)S'S(S)S*.   SQS+ jjr*SRSSS, jjr+STS- jr,S.r-g)Ur$   iU  a  B-spline construction tool.

Internal representation of a `B-spline`_ curve. The default configuration
of the knot vector is a uniform open `knot`_ vector ("clamped").

Factory functions:

    - :func:`fit_points_to_cad_cv`
    - :func:`fit_points_to_cubic_bezier`
    - :func:`open_uniform_bspline`
    - :func:`closed_uniform_bspline`
    - :func:`rational_bspline_from_arc`
    - :func:`rational_bspline_from_ellipse`
    - :func:`global_bspline_interpolation`
    - :func:`local_cubic_bspline_interpolation`

Args:
    control_points: iterable of control points as :class:`Vec3` compatible
        objects
    order: spline order (degree + 1)
    knots: iterable of knot values
    weights: iterable of weight values

)_control_points_basis_clampedNc                   [         R                  " U5      U l        [        U R                  5      n[	        U5      nX%:  a  [        SU SU SU 35      eUc  [        XRSS9nOL[        U5      nXR-   n[        U5      U:w  a  [        U S[        U5       S35      eUS   S	:w  a  [        U5      n[        X2XTS
9U l
        [        [        US U 5      5      S:H  =(       a    [        [        X2* S  5      5      S:H  U l        g )Nzgot z control points, need z or more for order of TrF   z knot values required, got .r   rx   )weightsr   )r   tupler   rD   rc   r   r2   rE   rp   r   r   r   r   )selfrI   r:   r;   r   rZ   required_knot_counts          rO   __init__BSpline.__init__q  s     $zz.9D(()E
=ug3E7:PQVPWX  =,UTJE%LE"'-5z00 *++Fs5zlRST  Qx3'.E%ACfu./14VSvw=P9QUV9VrP   c                    SU R                    SU R                   S[        U R                  5       5       S[        U R	                  5       5       S3	$ )NzBSpline degree=z, z control points, z knot values, z weights)rA   rZ   rD   r;   r   r   s    rO   __str__BSpline.__str__  sL    dkk]"TZZL 9"4::<014<<>"#8-	
rP   c                    U R                   $ )z4Control points as tuple of :class:`~ezdxf.math.Vec3`)r   r  s    rO   rI   BSpline.control_points  s     ###rP   c                ,    [        U R                  5      $ )z7Count of control points, (n + 1 in text book notation).)rD   r   r  s    rO   rZ   BSpline.count  s     4''((rP   c                .    U R                   R                  $ )zBiggest `knot`_ value.)r   max_tr  s    rO   r
  BSpline.max_t       {{   rP   c                .    U R                   R                  $ )zOrder (k) of B-spline = p + 1)r   r:   r  s    rO   r:   BSpline.order  r  rP   c                .    U R                   R                  $ )z"Degree (p) of B-spline = order - 1)r   rA   r  s    rO   rA   BSpline.degree  s     {{!!!rP   c                B    [        U R                  U R                  5      $ r   )r   r   r   r  s    rO   	evaluatorBSpline.evaluator  s    d&:&:;;rP   c                .    U R                   R                  $ )z?Returns ``True`` if curve is a rational B-spline. (has weights))r   is_rationalr  s    rO   r  BSpline.is_rational  s     {{&&&rP   c                    U R                   $ )z7Returns ``True`` if curve is a clamped (open) B-spline.)r   r  s    rO   
is_clampedBSpline.is_clamped  s     }}rP   c                    [        XUS9$ )z/Returns :class:`BSpline` defined by fit points.r=   )r   )rH   rA   r>   s      rO   from_fit_pointsBSpline.from_fit_points  s     ,F6JJrP   c                R    [        U R                  U R                  U5      5      SS9$ )zQReturns an ellipse approximation as :class:`BSpline` with `num`
control points.

r6   rA   )r   verticesr   )ellipsenums     rO   ellipse_approximationBSpline.ellipse_approximation  s*     ,W^^C01!
 	
rP   c                R    [        U R                  U R                  U5      5      SS9$ )zMReturns an arc approximation as :class:`BSpline` with `num`
control points.

r6   r  )r   r  angles)arcr!  s     rO   arc_approximationBSpline.arc_approximation  s#     ,CLLC,IRSTTrP   c                    [        U SS9$ )z_Returns the ellipse as :class:`BSpline` of 2nd degree with as few
control points as possible.

r   segments)r    )r   s    rO   from_ellipseBSpline.from_ellipse  s     -WqAArP   c                l    [        U R                  U R                  U R                  U R                  SS9$ )z[Returns the arc as :class:`BSpline` of 2nd degree with as few control
points as possible.

r   r*  )r   centerradiusstart_angle	end_angle)r&  s    rO   from_arcBSpline.from_arc  s,     )JJ

COOS]]Q
 	
rP   c                j    [        U R                  U R                  U R                  U R                  S9$ )zInterface to the `NURBS-Python <https://pypi.org/project/geomdl/>`_
package.

Returns a :class:`BSpline` object from a :class:`geomdl.BSpline.Curve`
object.

rI   r:   r;   r   )r$   ctrlptsr:   
knotvectorr   )curves    rO   from_nurbs_python_curveBSpline.from_nurbs_python_curve  s/      ==++""MM	
 	
rP   c           	        ^  U 4S jnT R                  [        T R                  5      T R                  U" 5       T R                  (       a  [        T R                  5       5      S9$ SS9$ )zJReturns a new :class:`BSpline` object with reversed control point
order.

c               3  n   >#    [        [        TR                  5       5      5       H
  n SU -
  v   M     g 7f)Nrr   )reversedrp   r;   )rd   r   s    rO   reverse_knots&BSpline.reverse.<locals>.reverse_knots  s)     odjjl;<Ag =s   25Nr6  )	__class__r>  rI   r:   r  r   )r   r?  s   ` rO   reverseBSpline.reverse  sf    	 ~~#D$7$78**/040@0@HT\\^,	  
 	
 GK	  
 	
rP   c                .    U R                   R                  $ )zReturns a tuple of `knot`_ values as floats, the knot vector
**always** has order + count values (n + p + 2 in text book notation).

)r   r;   r  s    rO   r;   BSpline.knots  s    
 {{   rP   c                .    U R                   R                  $ )z\Returns a tuple of weights values as floats, one for each control
point or an empty tuple.

)r   r   r  s    rO   r   BSpline.weights  s    
 {{"""rP   c                V    U R                   R                  U R                  U5      5      $ )zYApproximates curve by vertices as :class:`Vec3` objects, vertices
count = segments + 1.

)r  rH   r   r   r+  s     rO   approximateBSpline.approximate  s"    
 ~~$$T[[%:;;rP   c                    U R                  5       nX R                  S-
     nX R                     n[        R                  " X4US-   5      $ )z7Yield evenly spaced parameters for given segment count.r   )r;   r:   rZ   r   linspace)r   r+  r;   lower_boundupper_bounds        rO   r   BSpline.params  s@     

JJN+JJ'{{;X\BBrP   c              #    ^^^#    SUUU4S jjmU R                   m[        R                  " [        R                  " U R	                  5       5      5      n[        R
                  " U5      nUS   nTR                  U5      nUv   USS  H_  nXu-
  U-  nXW:  d  M  XX-   n	[        R                  " X5      (       a  Un	TR                  U	5      n
T" XjXY5       Sh  vN   U	nU
nXW:  a  MN  Ma     g N7f)a  Adaptive recursive flattening. The argument `segments` is the
minimum count of approximation segments between two knots, if the
distance from the center of the approximation segment to the curve is
bigger than `distance` the segment will be subdivided.

Args:
    distance: maximum distance from the projected curve point onto the
        segment chord.
    segments: minimum segment count between two knots

c              3     >#    X#-   S-  nTR                  U5      n [        XPU5      nUT:  a  Uv   g T	" XX$5       S h  vN   T	" XQXC5       S h  vN   g ! [         a    Sn N<f = f N( N7f)Ng      ?r   )pointr   ZeroDivisionError)
sestart_tend_tmid_tr   _distdistancer  subdivs
          rO   r\  "BSpline.flattening.<locals>.subdiv0  s~     _+E&A.qQ7 x!!777!!555 % 
 85sE   A-A A- A)A-A+A-A&#A-%A&&A-+A-r   r   N)rU  r   rV  r   rW  rs   rX  rs   )r  r   uniquer   r;   r   rS  r   )r   r[  r+  r;   seg_f64rJ   start_pointr   deltanext_t	end_pointr  r\  s    `         @@rO   
flatteningBSpline.flattening#  s     	6 	6 NN			"((4::<01**X&!Hooa()BVw&E&::f))F%OOF3	!+!DDD' &  Es   BC/>C/C-C/(C/c                8    U R                   R                  U5      $ )zOReturns point  for parameter `t`.

Args:
    t: parameter in range [0, max_t]

)r  rS  r   rJ   s     rO   rS  BSpline.pointN  s     ~~##A&&rP   c                8    U R                   R                  U5      $ )zVYields points for parameter vector `t`.

Args:
    t: parameters in range [0, max_t]

)r  rH   rg  s     rO   rH   BSpline.pointsW  s     ~~$$Q''rP   c                8    U R                   R                  X5      $ )a   Return point and derivatives up to `n` <= degree for parameter `t`.

e.g. n=1 returns point and 1st derivative.

Args:
    t: parameter in range [0, max_t]
    n: compute all derivatives up to n <= degree

Returns:
    n+1 values as :class:`Vec3` objects

)r  
derivativer   rJ   re   s      rO   rl  BSpline.derivative`  s     ~~((..rP   c                8    U R                   R                  X5      $ )a  Yields points and derivatives up to `n` <= degree for parameter
vector `t`.

e.g. n=1 returns point and 1st derivative.

Args:
    t: parameters in range [0, max_t]
    n: compute all derivatives up to n <= degree

Returns:
    List of n+1 values as :class:`Vec3` objects

)r  r   rm  s      rO   r   BSpline.derivativeso  s     ~~))!//rP   c                \  ^^^^ U R                   R                  (       a  U R                  T5      $ [        U R                   R                  5      m[        U R
                  5      mU R                  mSUUUU4S jjnTS::  d  TU R                  :  a  [        S5      eU R                   R                  T5      nUT:  a  [        S5      e[        UT-
  S-   US-   5       Vs/ s H
  oB" U5      PM     snTUT-
  S-   U& TR                  US-   T5        [        TU R                  T5      $ s  snf )zInsert an additional knot, without altering the shape of the curve.
Returns a new :class:`BSpline` object.

Args:
    t: position of new knot 0 < t < max_t

c                `   > TTU    -
  TU T-      TU    -
  -  nTU S-
     SU-
  -  TU    U-  -   $ Nr   rl   )indexr   cpointsr;   rf   rJ   s     rO   	new_point&BSpline.insert_knot.<locals>.new_point  sN    U5\!eEAI&6u&EFA519%Q/'%.12DDDrP   rx   Invalid position tr   )rt  rc   r   r   )r   r  _insert_knot_rationalrC   r;   r   rA   r
  r   r   rt   r   r$   r:   )r   rJ   rv  rd   r   ru  r;   rf   s    `   @@@rO   insert_knotBSpline.insert_knot  s	    ;;""--a00T[[&&'t++,KK	E 	E 8qDJJ 455KK!!!$q5 4558=a!eaiQ8O!P8O1)A,8O!PA	AQUAw

E22 "Qs    D)c                p  ^^^	^
 U R                   R                  (       d  [        S5      e[        U R                   R                  5      m	[        U 5      mU R                  m
SUU	U
U4S jjnTS::  d  TU R                  :  a  [        S5      eU R                   R                  T5      nUT
:  a  [        S5      eTR                  5       n[        UT
-
  S-   US-   5       Vs/ s H
  oR" U5      PM     snXCT
-
  S-   U& [        U5      u  pgT	R                  US-   T5        [        X`R                  T	US9$ s  snf )z&Knot insertion for rational B-splines.zRequires a rational B-splines.c                `   > TTU    -
  TU T-      TU    -
  -  nTU S-
     SU-
  -  TU    U-  -   $ rs  rl   )rt  r   	hg_pointsr;   rf   rJ   s     rO   rv  0BSpline._insert_knot_rational.<locals>.new_point  sO    E%L(U519-=e-LMAUQY'1q51Ie4Dq4HHHrP   rx   rx  r   r;   r   )rt  rc   r   np.typing.NDArray)r   r  	TypeErrorrC   r;   to_homogeneous_pointsrA   r
  r   r   tolistrt   from_homogeneous_pointsr   r$   r:   )r   rJ   rv  rd   
new_pointsr   rH   r   r~  r;   rf   s    `      @@@rO   ry  BSpline._insert_knot_rational  s   {{&&<==!$++"3"34'<T'B		I 	I 8qDJJ 455&&q)q5 455#**,
;@QAPQE;R$S;RaYq\;R$S
q519q!1*=QUAvzzHH	 %Ts    D3c                >    U nU H  nUR                  U5      nM     U$ )zInsert multiple knots, without altering the shape of the curve.
Returns a new :class:`BSpline` object.

Args:
    u: vector of new knots t and for each t: 0 < t  < max_t

)rz  )r   r   splinerJ   s       rO   knot_refinementBSpline.knot_refinement  s(     A''*F rP   c                    UR                  U R                  5      n[        X R                  U R	                  5       U R                  5       5      $ )zaReturns a new :class:`BSpline` object transformed by a
:class:`Matrix44` transformation matrix.

)transform_verticesrI   r$   r:   r;   r   )r   r   ru  s      rO   	transformBSpline.transform  s9    
 &&t':':;w

DJJL$,,.IIrP   c              #  
  #    U R                   R                  (       a  [        S5      eU R                  (       d  [        S5      eU R                  S-
  nU R
                  nU R                   R                  nU R                  nS/[        U5      -  nX-   S-   nUnUS-   n[        USUS-    5      n	X:  GaL  [        /US-   -  n
UnX:  aR  [        R                  " X8S-      X8   5      (       a/  US-  nX:  a%  [        R                  " X8S-      X8   5      (       a  M/  X-
  S-   nX:  a  X8   X7   -
  n[        X,S5       H  nXX~-      X7   -
  -  X^U-
  S-
  '   M     X,-
  n[        SUS-   5       HR  nX-
  nX-   n[        UUS-
  S5       H%  nUUU-
     nU	U   U-  U	US-
     SU-
  -  -   U	U'   M'     X:  d  MK  X   U
U'   MT     U	v   X:  a-  [        X,-
  US-   5       H  nXHU-
  U-      X'   M     UnUS-  nU
n	X:  a  GMK  gg7f)	u  Decompose a non-rational B-spline into multiple Bézier curves.

This is the preferred method to represent the most common non-rational
B-splines of 3rd degree by cubic Bézier curves, which are often supported
by render backends.

Returns:
    Yields control points of Bézier curves, each Bézier segment
    has degree+1 control points e.g. B-spline of 3rd degree yields
    cubic Bézier curves of 4 control points.

z!Rational B-splines not supported.zClamped B-Spline required.r   rx   r   r?   rr   N)r   r  r  r  rZ   rA   r;   r   rD   rC   r   r   r   rt   )r   re   rf   r;   rI   alphasr   r   r   bezier_pointsnext_bezier_pointsr   multnumerr   rsaverU  rd   alphas                       rO   bezier_decompositionBSpline.bezier_decomposition  s;     ;;""?@@899JJNKK!!--U#EAIE^AA67e")a!e!4A%DLL1uux@@Q %DLL1uux@@519Dx58+q+A+0!%L584K+LFt8a<( ,Hq!a%A5DA"1a!eR0 &q1u+8+;e+CmEG 5[G* ,*a( 1
 u3@3C*40 )  uqxQ/A,:q519,E&) 0Q 29 ees   DHBH8AHHc                    Uc*  [        U R                  U R                  U5      5      5      nO[        U R                  U5      5      nSSKJn  U" U5      $ )uA  Approximate arbitrary B-splines (degree != 3 and/or rational) by
multiple segments of cubic Bézier curves. The choice of cubic Bézier
curves is based on the widely support of this curves by many render
backends. For cubic non-rational B-splines, which is maybe the most
common used B-spline, is :meth:`bezier_decomposition` the better choice.

1. approximation by `level`: an educated guess, the first level of
   approximation segments is based on the count of control points
   and their distribution along the B-spline, every additional level
   is a subdivision of the previous level.

E.g. a B-Spline of 8 control points has 7 segments at the first level,
14 at the 2nd level and 28 at the 3rd level, a level >= 3 is recommended.

2. approximation by a given count of evenly distributed approximation
   segments.

Args:
    level: subdivision level of approximation segments (ignored if
        argument `segments` is not ``None``)
    segments: absolute count of approximation segments

Returns:
    Yields control points of cubic Bézier curves as :class:`Bezier4P`
    objects

r   )rR   )rC   rH   approximation_paramsrJ  bezier_interpolationrR   )r   levelr+  rH   rR   s        rO   cubic_bezier_approximation"BSpline.cubic_bezier_approximation	  sK    < $++d&?&?&FGHF$**845FD)&11rP   c                "   [        [        U R                  S5      5      n[        U5      S:X  a  U$ U R                  S:w  a   U R                  nU Vs/ s H  oDU-  PM	     nn[        US-
  5       H  n[        [        U5      5      nM     U$ s  snf )aM  Returns an educated guess, the first level of approximation
segments is based on the count of control points and their distribution
along the B-spline, every additional level is a subdivision of the
previous level.

E.g. a B-Spline of 8 control points has 7 segments at the first level,
14 at the 2nd level and 28 at the 3rd level.

r<   r   rr   r   )rC   r   r   rD   r
  rt   subdivide_params)r   r  r   r
  rf   _s         rO   r  BSpline.approximation_params/  s     od&:&:GDEv;!M::JJE)/0A%iF0uqy!A*623F " 1s   Bc                    [        X5      $ )a  Returns a new :class:`BSpline` with a t-times elevated degree.

Degree elevation increases the degree of a curve without changing the shape of the
curve. This method implements the algorithm A5.9 of the "The NURBS Book" by
Piegl & Tiller.

.. versionadded:: 1.4

)degree_elevationrg  s     rO   r  BSpline.degree_elevationC  s      ((rP   :0yE>d      epsilonmax_iterationsinitc               ,    [        U [        U5      X#US9$ )a  Returns the parameter t for a point on the curve that is closest to the input
point.

This is an iterative search using Newton's method, so there is no guarantee
of success, especially for splines with many turns.

Args:
    point(UVec): point on the curve or near the curve
    epsilon(float): desired precision (distance input point to point on curve)
    max_iterations(int): max iterations for Newton's method
    init(int): number of points to calculate in the initialization phase

.. versionadded:: 1.4

r  )point_inversionr   )r   rS  r  r  r  s        rO   r  BSpline.point_inversionO  s    $ $u+wTX
 	
rP   c                    [        X5      $ )zReturns a B-spline measurement tool.

All measurements are based on the approximated curve.

Args:
    segments: count of segments for B-spline approximation.

.. versionadded:: 1.4

)MeasurementrI  s     rO   measureBSpline.measuree  s     4**rP   c                    [        X5      $ )zSplits the B-spline at parameter `t` and returns two new B-splines.

Raises:
    ValuerError: t out of range 0 < t < max_t

.. versionadded:: 1.4

)split_bsplinerg  s     rO   splitBSpline.splitr  s     T%%rP   )r   r   r   )r8   NN)rI   Iterable[UVec]r:   rc   r;   Optional[Iterable[float]]r   r  )r   zSequence[Vec3])r   rc   r   rs   )r   r   )r@   r<   )rH   r  r   r$   )   )r   r   r!  rc   r   r$   )r&  r   r!  rc   r   r$   )r   r   r   r$   )r&  r   r   r$   )r   r$   )r   Sequence[float])r   )r+  rc   r   Iterable[Vec3])r+  rc   r   Iterable[float])r8   )r[  rs   r+  rc   r   zIterator[Vec3])rJ   rs   r   r   )rJ   r  r   r  )r6   )rJ   rs   re   rc   r   
list[Vec3])rJ   r  re   rc   r   Iterable[list[Vec3]])rJ   rs   r   r$   )r   r  r   r$   )r   r   r   r$   )r   r  )r@   N)r  rc   r+  zOptional[int]r   zIterable[Bezier4P])r@   )r  rc   r   r  )rJ   rc   r   r$   )rS  r   r   rs   )r  )r+  rc   r   r  )rJ   rs   r   tuple[BSpline, BSpline]).__name__
__module____qualname____firstlineno____doc__	__slots__r   r  propertyrI   rZ   r
  r:   rA   r  r  r  staticmethodr  r"  r'  r,  r3  r:  rB  r;   r   rJ  r   rd  rS  rH   rl  r   rz  ry  r  r  r  r  r  r  r  r  r  __static_attributes__rl   rP   rO   r$   r$   U  s   2 :I
 +/-1W&W W )	W
 +W:
 $ $ ) ) ! ! ! ! " " < < ' '   K K 
 
 U U B B 
 
 
 

"!#<C)(V'(/0 3<I6J:3z 9=$2$2(5$2	$2L(
) '+3Q

	
,+
&rP   c              #     #    [        [        U 5      S-
  5       H  nX   v   X   XS-      -   S-  v   M     U S   v   g 7f)Nr   r   r?   )rt   rD   )rf   r   s     rO   r  r    sE     3q6A:d
taAh#%%  B%Ks   >A c                j    [         R                  " U 5      n[        [        U5      USS9n[	        XXBS9$ )aK  Creates an open uniform (periodic) `B-spline`_ curve (`open curve`_).

This is an unclamped curve, which means the curve passes none of the
control points.

Args:
    control_points: iterable of control points as :class:`Vec3` compatible
        objects
    order: spline order (degree + 1)
    weights: iterable of weight values

Fr   )r:   r;   r   )r   r   r1   rD   r$   )rI   r:   r   r   r;   s        rO   r"   r"     s2    " jj0OO 4euME>eMMrP   c                    [         R                  " U 5      nUR                  USUS-
   5        Ub"  [        U5      nUR                  USUS-
   5        [        X1U5      $ )a.  Creates a closed uniform (periodic) `B-spline`_ curve (`open curve`_).

This B-spline does not pass any of the control points.

Args:
    control_points: iterable of control points as :class:`Vec3` compatible
        objects
    order: spline order (degree + 1)
    weights: iterable of weight values

Nr   )r   rC   r~   r"   )rI   r:   r   r   s       rO   r#   r#     s^      ii/O?;UQY78w-w{+,@@rP   c                   ^ ^ [        T 5      m [        T5      m[        R                  " US-  5      nU[        R                  " [	        X#5      5      -   n[        XVU5      u  pxn	[        U U4S jU 5       UU	SS9$ )ac  Returns a rational B-splines for a circular 2D arc.

Args:
    center: circle center as :class:`Vec3` compatible object
    radius: circle radius
    start_angle: start angle in degrees
    end_angle: end angle in degrees
    segments: count of spline segments, at least one segment for each
        quarter (90 deg), default is 1, for as few as needed.

h  c              3  4   >#    U  H  nTUT-  -   v   M     g 7fr   rl   )rz   rf   r/  r0  s     rO   r{   ,rational_bspline_from_arc.<locals>.<genexpr>  s     F~!!f*-~r}   r@   rI   r   r;   r:   )r   rs   r   radiansr   nurbs_arc_parametersr$   )
r/  r0  r1  r2  r+  	start_radend_radrI   r   r;   s
   ``        rO   r   r     sr    $ &\F6]F[3./I$,,'9+'QRRG%9)h%W"NUF~F	 rP   r   c                   ^ ^ T R                   [        R                  -  nUT R                  -   nSUU 4S jjn[	        X#U5      u  mpV[        U" 5       UUSS9$ )u  Returns a rational B-splines for an elliptic arc.

Args:
    ellipse: ellipse parameters as :class:`~ezdxf.math.ConstructionEllipse`
        object
    segments: count of spline segments, at least one segment for each
        quarter (π/2), default is 1, for as few as needed.

c               3     >#    [        TR                  5      n TR                  nTR                  nT H%  nXUR                  -  -   X#R
                  -  -   v   M'     g 7fr   )r   r/  
major_axis
minor_axisxy)r/  x_axisy_axisrf   rI   r   s       rO   transform_control_points?rational_bspline_from_ellipse.<locals>.transform_control_points  sP     gnn%####AACC<'&33,66  s   AAr@   r  )r   r  )start_paramr   tau
param_spanr  r$   )r   r+  r1  r2  r  r   r;   rI   s   `      @rO   r    r      sg     %%0Kg000I7 7 &:&"NG /1	 rP   c           	         US:  a  [        S5      eX-
  n[        [        R                  " U[        -  5      U5      nX4-  nUS-  n[        R
                  " U5      n[        [        R
                  " U 5      [        R                  " U 5      5      /nS/n	U n
S[        R
                  " US-  5      -  n[        U5       H  nX-  n
UR                  [        [        R
                  " U
5      U-  [        R                  " U
5      U-  5      5        U	R                  U5        X-  n
UR                  [        [        R
                  " U
5      [        R                  " U
5      5      5        U	R                  S5        M     / SQnS[        [        U5      S-   S5      S-
  S-  S-   -  nUnUS:  a  UR                  X45        X-  nUS:  a  M  UR                  S/[        [        U5      S5      [        U5      -
  -  5        XU4$ )	u5  Returns a rational B-spline parameters for a circular 2D arc with center
at (0, 0) and a radius of 1.

Args:
    start_angle: start angle in radians
    end_angle: end angle in radians
    segments: count of segments, at least one segment for each quarter (π/2)

Returns:
    control_points, weights, knots

r   z!Invalid argument segments (>= 1).r6   rr   r   )rx   rx   rx   r8   r@   )rE   ri   r   ceilPI_2cosr   sinrt   r   rD   r~   r0   )r1  r2  r+  delta_angle	arc_countsegment_anglesegment_angle_2
arc_weightrI   r   angledr  r;   stepgs                   rO   r  r    s    !|<==)KDIIkD018<I+M#a'O/*J 488K0$((;2GHINeGEdhh}s*++A9 d488E?Q#6!8KLMz" 	 d488E?DHHUODEs  E3s>*Q.2Q6#=CDDA
c'aV		 c' 
LL#.s>/BAFUSTUE))rP   c                p   ^ ^^^ 0 m[        T 5      m SUUUU 4S jjmT" [        U5      [        U5      5      $ )a  B-spline basis_vector function.

Simple recursive implementation for testing and comparison.

Args:
    u: curve parameter in range [0, max(knots)]
    index: index of control point
    degree: degree of B-spline
    knots: knots vector

Returns:
    float: basis_vector value N_i,p(u)

c                d  >  TX4   $ ! [          a    US:X  a  TU    T	s=::  a  TU S-      :  a  O  OSOSnOmTX-      TU    -
  nU(       a  T	TU    -
  U-  T" XS-
  5      -  OSnTX-   S-      TU S-      -
  nU(       a   TX-   S-      T	-
  U-  T" U S-   US-
  5      -  OSnXE-   nUTX4'   Us $ f = f)Nr   r   rx   )KeyError)
r   rf   retval	dominatorf1f2r   cacher;   r   s
         rO   r   bspline_basis.<locals>.N@  s    	!=  	Av#Ah!:eAEl:!!%L583	AJa%(li/!A1u+=PS!!%!),uQU|;	 ! 1519%)Y61q5!a%H  "E1&MM!	s   	 B#B/.B/)r   rc   rf   rc   r   rs   )rs   rc   )r   rt  rA   r;   r   r  s   `  `@@rO   bspline_basisr  .  s4     +-EaA * SZV%%rP   c           	         [        U5      X-   S-   :X  d   e[        U5       Vs/ s H  n[        XX#5      PM     nn[        R                  " XS   5      (       a  SUS'   U$ s  snf )a[  Create basis_vector vector at parameter u.

Used with the bspline_basis() for testing and comparison.

Args:
    u: curve parameter in range [0, max(knots)]
    count: control point count (n + 1)
    degree: degree of B-spline (order = degree + 1)
    knots: knot vector

Returns:
    list[float]: basis_vector vector, len(basis_vector) == count

r   r?   rr   )rD   rt   r  r   r   )r   rZ   rA   r;   rt  r   s         rO   bspline_basis_vectorr  X  sl    " u:%.1,---<A%L<H5a.L 
  ||ARy!!b	Ls   A!c           	        [        U5      nUS:  a  U $ U R                  nU R                  (       a  Sn[        U 5      nO"Sn[        R
                  " U R                  5      n[        R
                  " U R                  5       5      n[        U5      S-
  nXb-   S-   nX!-   nUS-  n	[        R                  " [        U5      SU-   -  U4S9n
[        R                  " USU-   -  5      n[        R                  " X!-   S-   US-   4S9n[        R                  " US-   U4S9n[        R                  " X!-   S-   U4S9n[        R                  " US-
  U4S9n[        R                  " US-
  5      nSUS'   SXU4'   [        R                  n[        SU	S-   5       H\  nSU" UU5      -  n[        UU5      n[        [        SUU-
  5      US-   5       H!  nUU" UU5      -  U" UUU-
  5      -  UUU4'   M#     M^     [        U	S-   U5       HC  n[        UU5      n[        [        SUU-
  5      US-   5       H  nXU-
  UU-
  4   UUU4'   M     ME     UnUS-   nS	nUnUS-   nSnUS   nUS   U
S'   UUS
US-   & US
US-    US
US-   & UU:  Ga
  UnUU:  aW  [        R                   " UU   UUS-      5      (       a2  US-  nUU:  a'  [        R                   " UU   UUS-      5      (       a  M2  UU-
  S-   nUU-   U-   nUU   nUnUU-
  nUS:  a	  US-   S-  n OSn US:  a  UUS-   S-  -
  n!OUn!US:  a  UU-
  n"[        UUS	5       H  n#U"UUU#-      U-
  -  UU#U-
  S-
  '   M     [        SUS-   5       HQ  nUU-
  n$UU-   n%[        UU%S-
  S	5       H)  n#UU#U%-
     UU#   -  SUU#U%-
     -
  UU#S-
     -  -   UU#'   M+     X   UU$'   MS     [        U US-   5       HM  nSUU'   [        UU5      n[        [        SUU-
  5      US-   5       H  nUU   UUU4   UU   -  -   UU'   M     MO     US:  a  US-
  n&Un'UU-
  n(UUUS-
     -
  U(-  n)[        SU5       H  n*U&nU'nUU-
  S-   n+UU-
  U*:  a  UU:  a+  UUU   -
  UUU   -
  -  n,U,U
U   -  SU,-
  U
US-
     -  -   U
U'   UU :  aR  UU*-
  UU-
  U-   ::  a)  UUUU*-
     -
  U(-  n-U-UU+   -  SU--
  UU+S-      -  -   UU+'   OU)UU+   -  SU)-
  UU+S-      -  -   UU+'   US-  nUS-  nU+S-  n+UU-
  U*:  a  M  U&S-  n&U'S-  n'M     UU:w  a  UU-
  nUUUUU-   & UU-  n[        U U!S-   5       H  nUU   U
U'   US-  nM     UU:  a&  US
U US
U& UUU-
  U-   US-    UUUS-   & UnUS-  nUnOUUUUU-   S-   & UU:  a  GM
  UU-
  S-
  n.U.S-   n/US-   n0S
n1U
S
U/2S
S24   n2US:X  a=  U
S
U/2S4   n1[#        U2U15       VV3s/ s H  u  nn3UU3-  PM     n2nn3U1R%                  5       n1['        U2U0U1US
U/U0-    S9$ s  sn3nf )a	  Returns a new :class:`BSpline` with a t-times elevated degree.

Degree elevation increases the degree of a curve without changing the shape of the
curve. This function implements the algorithm A5.9 of the "The NURBS Book" by
Piegl & Tiller.

.. versionadded:: 1.4

r   r8   r@   r6   )shaperr   r   r   r   r?   Nrx   )r:   r   r;   )rc   rA   r  r  r   r   rI   r;   rD   zerosr   binomial_coefficientrt   minri   r   r   r   r  r$   )4r  rJ   rf   dimPwUre   r   phph2QwUhbezalfsbptsebptsNextbptsalfsbinomr   invmpir   mhkindr  r   r   cinduamuluboldrlbzrbzr  rd   r  rU  firstlastdenbettrkjalfgamnh
count_cptsr:   r   ru  ws4                                                       rO   r  r  s  s    	AA1uA"6* XXf++, 	 A 	B!A		A	
B
'C 
RAE*C0	1B 
!q1u+	B hhaeaiQ/0G 881q5#,'D HHAEAIs+,E xxq1ucl+H 88AE?DGDMGEN''E1cAgE"aL !Qis1a!e}cAg.A%1+-aQ?GAqDM / 
 37B!Qis1a!e}cAg.A#FAEM2GAqDM /   
B6D
A	A	AAD	
1BqEBqE BxaL
 wQKD1q5M
a%1u4<<!aAh77FA 1u4<<!aAh77!eai#X\qTG!8!8/CCq5A!|#CCq5GE1c2&$)Qq1uX]$;QWq[! '1a!e_1u!Gq!a%,A"1q5kDG3sT!a%[7HDQRUVQVK6WWDG -!% % sBF#A E!Ha)C3q!a%=#'2 8gadmd1g&==a 3 $ !81HEDr'C4!8$+CAtnX\!ebj4x!BqEzb2a5j9 #besSyBq1uI.E E1Cxr6TBY%55#%1r6
?c"9C(+eBi39bSTf:U(UE"I(+eBi39bSTf:U(UE"IFAFA!GB !ebj 
	) %, 6 T	A"$BtdQhAIDsC!G$AQxBtHAID % q5  |D!H !QQU3DQUOAFAB (*BtdRi!m$w a%z 
b1BaJFEG*bqb!G
ax[j[!^$%('%:;%:TQ1q5%:;.."ugR8L*u:L5M  <s   Xc           
        [         R                  " U R                  5       [         R                  S9n[	        U5      (       d   [         R
                  " U R                  5      n[         R                  " [        U R                  U5       VVs/ s H2  u  p#UR                  U-  UR                  U-  UR                  U-  U4PM4     snn5      $ s  snnf )Nr   )r   r   r   r   rD   onesrZ   r   rI   r  r  z)r  r   ro   r(  s       rO   r  r  7  s    hhv~~'rzz:Gw<<''&,,'88478M8Mw4WX4WDA!##'1337ACC!GQ	'4WX Xs   9C
c                    / n/ nU  HB  n[        US   5      nUR                  [        US S 5      U-  5        UR                  U5        MD     X4$ )Nr@   )rs   r   r   )r~  rH   r   rS  r(  s        rO   r  r  A  sV     FG%(Od5!9o)*q  ?rP   r  r  r  r  c               Z   U R                   n[        S5      nUS-  n[        R                  " SXTSS9n[	        U R                  U5      5      n	[        X5       H*  u  pUR                  U5      nX:  d  M  [        U
5      nUnM,     Sn[        U5       H  nU R                  USS9u  pX-
  nUR                  nX:  a    U$ [        R                  " Xl5      (       a  US-  nUS:  a    U$ OSnUnUUR                  U5      UR                  U5      -  -  nUS:  a  SnM  Xu:  d  M  UnM     U$ )	a  Returns the parameter t for a point on the curve that is closest to the input
point.

This is an iterative search using Newton's method, so there is no guarantee
of success, especially for splines with many turns.

Args:
    spline(BSpline): curve
    point(Vec3): point on the curve or near the curve
    epsilon(float): desired precision (distance input point to point on curve)
    max_iterations(int): max iterations for Newton's method
    init(int): number of points to calculate in the initialization phase

.. versionadded:: 1.4

infr6   r   Tendpointr   r   rx   )r
  rs   r   rM  rC   rH   r   r[  rt   rl  r   r   r   r   )r  rS  r  r  r  r
  prev_distancer   rJ   
chk_pointsr   rf   r[  no_progress_counter	iterationdpdudiffs                    rO   r  r  M  sK   & LLE%LM	A 	AuT2AfmmA&'JQ#>>!$#b	A$M	 $  !>*	##A#+ y >>" H! <<001$"Q& H ' #$  	
TXXd^dhhtn,, s7AYA5 +6 HrP   c                  h    \ rS rSrSrSS jr\SS j5       r\SS j5       r	SS jr
SS jrSS jrS	rg
)r  i  zjB-spline measurement tool.

All measurements are based on the approximated curve.

.. versionadded:: 1.4

c                $   [        U[        5      (       d  [        S[        U5       35      e[	        U5      nUS:  a  [        SU 35      eXl        [        R                  " SUR                  US-   SS9U l
        [        U R                  R                  U R                  5      5      n[        U5      nUR                  U l        UR                  U l        U R!                  U5      U l        [        R$                  " U R"                  5      U l        g )NzBSpline instance expected, got r   zinvalid segment count: rx   Tr/  )r   r$   r  typerc   rE   _spliner   rM  r
  _parametersrC   rH   r   extminextmax_measure
_distancescumsum_offsets)r   r  r+  rH   bboxs        rO   r   Measurement.__init__  s    &'**=d6l^LMMx=a<6xjABB;;sFLL(Q,QUVdll))$*:*:;<6"kkkk--/		$//2rP   c                    U S   n[         R                  " [        U 5      [         R                  S9n[	        U 5       H  u  p4UR                  U5      X#'   UnM     U$ )Nr   r   )r   r  rD   r   	enumerater[  )rH   prev	distancesrt  rS  s        rO   r>  Measurement._measure  sR    ayHHS[

;	%f-LE#}}U3ID . rP   c                2    [        U R                  S   5      $ )z0Returns the approximated length of the B-spline.r?   )rs   rA  r  s    rO   lengthMeasurement.length  s     T]]2&''rP   c                    US::  a  gXR                   R                  :  a  U R                  $ U R                  n[        R
                  " X!SS9nX#   nX#S-      nU R                  US-      X-
  -  XT-
  -  n[        U R                  U   U-   5      $ )zVReturns the distance along the curve from the start point for then given
parameter t.
rx   rightsider   )	r:  r
  rJ  r;  r   searchsortedr?  rs   rA  )r   rJ   r   rt  r   t2r[  s          rO   r[  Measurement.distance  s     8""";;!!8]AI??519-8BGDT]]5)H455rP   c                2   [         R                  " U R                  USS9nUS::  a  gU R                  nU[	        U5      :  a  U R
                  R                  $ US-
  nXR                  U   -
  nX4   nX2   n[        XgU-
  XPR                  U   -  -  -   5      $ )zSReturns the parameter t for a given distance along the curve from the
start point.
rM  rN  r   rx   r   )	r   rP  rA  r;  rD   r:  r
  rs   r?  )r   r[  rt  r   rF  r1  r   rQ  s           rO   param_atMeasurement.param_at  s     xgFA:!!CK<<%%%qy ==#66\]R7}u7M'MNNOOrP   c                   US:  a  [        SU 35      eU R                  nX!-  nUnU R                  R                  n/ nXB:  aH  U R	                  U5      n[
        R                  " XW5      (       d  UR                  U5        XC-  nXB:  a  MH  U$ )aN  Returns the interpolated B-spline parameters for dividing the curve into
`count` segments of equal length.

The method yields only the dividing parameters, the first (0.0) and last parameter
(max_t) are not included e.g. dividing a B-spline by 3 yields two parameters
[t1, t2] that divides the B-spline into 3 parts of equal length.

r   zinvalid count: )rE   rJ  r:  r
  rT  r   r   r   )r   rZ   total_length
seg_lengthr[  r
  resultrJ   s           rO   divideMeasurement.divide  s     19ug677"kk!)
"" %h'A<<))a "H	 %
 rP   )r?  rA  r;  r:  r=  r<  N)r  r$   r+  rc   r   None)rH   r  r   r  r  )rJ   rs   r   rs   )r[  rs   r   rs   )rZ   rc   r   r   )r  r  r  r  r  r   r  r>  r  rJ  r[  rT  rZ  r  rl   rP   rO   r  r    sD    3   ( (6P rP   r  c                Z   SnX:  a  [        S5      eXR                  U-
  :  a  [        S5      eU R                  n[        R                  " X15      nU R                  U5      n [        R                  " U R                  5       [        R                  S9n[        R                  " XQSS9nUSU nXVS n[        R                  " XH45      nU R                  n	[        U5      U-
  n
U	SU
 nXS n/ n/ nU R                  5       n[        U5      (       a	  USU
 nXS n[        XX}S9[        XXS94$ )	zsSplits a B-spline at a parameter t.

Raises:
    ValuerError: t out of range 0 < t < max_t

.. versionadded:: 1.4

g-q=zt must be greater than 0zt must be smaller than max_tr   rM  rN  Nr  )rE   r
  r:   r   fullr  r   r;   r   rP  concatenaterI   rD   r   r$   )r  rJ   tolr:   r   r;   r   knots1knots2rH   split_indexpoints1points2weights1weights2r   s                   rO   r  r    s4    Cw344<<#788LLE 	A##A&FHHV\\^2::6E??5'2D 5D\F5\F ^^QK(F ""Ff+%K\k"G\"G "H "HnnG
7||<K(<(f?f? rP   r   )rG   r  rB   Optional[Iterable[UVec]]r   r$   )rG   r  r   r$   )r@   Nr<   )
rG   r  rA   rc   rB   rh  r>   strr   r$   )z5-pointsN)rG   r  r>   ri  rB   rh  r   r$   )rZ   rc   r:   rc   r   rc   )T)r:   rc   r   rc   )r;   r  r   r   )F)rZ   rc   r:   rc   r   r   )rX   F)re   rc   rf   rc   rJ   r  r   r   )re   rc   rf   rc   rJ   r  r   r   )r   zlist | linalg.MatrixrA   rc   r   zlinalg.Solver)rX   )
rG   zSequence[UVec]rA   rc   r[   r  r\   ri  r   tuple[list[Vec3], list[float]])rG   r  rM   r   rN   r   rA   rc   r[   r  r\   ri  r   rj  )rG   r  r   rj  )
rG   r  r   r  rA   rc   r[   r  r   rj  )rG   r  rB   r  r   rj  )rf   r   r   r  )r8   N)rI   r  r:   rc   r   r  r   r$   )r  r   r   r  r   )r/  r   r0  rs   r1  rs   r2  rs   r+  rc   r   r$   )r   )r   r   r+  rc   r   r$   )r1  rs   r2  rs   r+  rc   )
r   rs   rt  rc   rA   rc   r;   r  r   rs   )
r   rs   rZ   rc   rA   rc   r;   r  r   r   )r  r$   rJ   rc   r   r$   )r  r$   r   r  )r~  zIterable[Sequence[float]]r   rj  )r  r$   rS  r   r   rs   )r  r$   rJ   rs   r   r  )Ir  
__future__r   typingr   r   r   r   r   r	   r
   r   numpyr   rT   r   r   r   r   r   r   r   r   r   rB  r   r   ezdxf.lldxf.constr   r   r   r   r   __all__r   r!   r   r   r0   r3   r4   rp   r1   r2   r*   r+   r,   r-   r.   r/   r   r%   r&   r'   r(   r)   r$   r  r"   r#   r   pir  r    r  r  r  r  r  r  r  r  r  rl   rP   rO   <module>rq     s    #    
 
 
   + H *.**&* *Z,2 )-	SSS 'S 	S
 Sp )-'9'9'9 ''9 	'9T2$	4K&6 GL&F
&F&F&&F&FR*&&&#L06 #,	$3$3$3 $3  	$3
 $$3Z #,333333 33 	33
 33  33 $33l>3>3#>3B>3>3>3 >3 	>3
 $>3B6!6!&06!#6!rg& g&T )-N"NN 'N 	N0 )-A"AA 'A 	A2   	
  @ ww} 34 ,/B3*l'&T"%.=6 @ @F	(	#	 .2#A<< <
<~Z Zz-rP   