nurbspy.jax.nurbs_curve module#

class nurbspy.jax.nurbs_curve.NurbsCurve(control_points=None, weights=None, degree=None, knots=None)[source]#

Bases: Module

Create a NURBS (Non-Uniform Rational Basis Spline) curve object

Parameters:
control_pointsndarray with shape (ndim, n+1)

Array containing the coordinates of the control points The first dimension of P spans the coordinates of the control points (any number of dimensions) The second dimension of P spans the u-direction control points (0,1,…,n)

weightsndarray with shape (n+1,)

Array containing the weight of the control points

degreeint

Degree of the basis polynomials

knotsndarray with shape (r+1=n+p+2,)

The knot vector in the u-direction Set the multiplicity of the first and last entries equal to p+1 to obtain a clamped NURBS

Methods

get_arclength([u1, u2, tol, method])

Dispatch to an explicit arc-length method (adaptive by default).

get_arclength_ode([u1, u2, tol, atol, rtol, ...])

Integrate speed with knot-aware Dopri5 and local error controls.

get_arclength_quad_adaptive([u1, u2, tol, ...])

Integrate speed using adaptive knot-aware Gauss-Kronrod quadrature.

get_arclength_quad_fixed([u1, u2, n_points])

Compute the arc length of the NURBS curve over the parameter interval [u₁, u₂] using fixed-point numerical quadrature.

get_binormal(u)

Evaluate the unit binormal vector along the curve for the given u-parameterization.

get_curvature(u)

Evaluate the curvature of the curve for the input u-parametrization

get_derivative(u, order)

Evaluate the derivative of the curve for the input u-parametrization

get_normal(u)

Evaluate the unit normal vector along the curve for the given u-parameterization.

get_tangent(u)

Evaluate the unit tangent vector along the curve for the given u-parameterization.

get_torsion(u)

Evaluate the torsion of the curve for the input u-parametrization

get_value(u)

Evaluate the coordinates of the curve for the input u parametrization

plot([fig, ax, curve, control_points, ...])

Create a plot and return the figure and axes handles

plot_control_points(fig, ax[, linewidth, ...])

Plot the control points of the NURBS curve

plot_curve(fig, ax[, linewidth, linestyle, ...])

Plot the coordinates of the NURBS curve

plot_frenet_serret(fig, ax[, frame_number, ...])

Plot some Frenet-Serret reference frames along the NURBS curve

project_points(Q_all[, tol, maxiter, ...])

Project query columns using sampled initialization and one local solve.

reparametrize_by_arclength([tol, max_steps, ...])

Return a dense ODE map u_of_s and the total arc length.

reparametrize_by_coordinate([dim, tol])

Construct a callable function that reparametrizes the NURBS curve by one of its coordinate components, returning the corresponding parameter values u(x).

rescale_plot(fig, ax)

Adjust the aspect ratio of the figure

plot_curvature

plot_torsion

Notes

This class includes methods to compute:

  • Curve coordinates for any number of dimensions

  • Analytic curve derivatives of any order and number of dimensions

  • The unitary tangent, normal and binormal vectors (Frenet-Serret reference frame) in 2D and 3D

  • The analytic curvature and torsion in 2D and 3D

  • The arc length of the curve in any number of dimensions.

    The arc length is compute by numerical quadrature using analytic derivative information

The class can be used to represent polynomial and rational Bézier, B-Spline and NURBS curves The type of curve depends on the initialization arguments

  • Polymnomial Bézier: Provide the array of control points

  • Rational Bézier: Provide the arrays of control points and weights

  • B-Spline: Provide the array of control points, degree and knot vector

  • NURBS: Provide the arrays of control points and weights, degree and knot vector

In addition, this class supports operations with real and complex numbers The data type used for the computations is detected from the data type of the arguments Using complex numbers can be useful to compute the derivative of the shape using the complex step method

References

The NURBS Book. See references to equations and algorithms throughout the code L. Piegl and W. Tiller Springer, second edition

Curves and Surfaces for CADGD. See references to equations the source code G. Farin Morgan Kaufmann Publishers, fifth edition

All references correspond to The NURBS book unless it is explicitly stated that they come from Farin’s book

P: Array#
U: Array#
W: Array#
curve_type: str#
get_arclength(u1=0.0, u2=1.0, tol=None, *, method='quad_adaptive', **options)[source]#

Dispatch to an explicit arc-length method (adaptive by default).

method is static under eqx.filter_jit: only the selected method is traced/compiled, and AD acts on that calculation. The choices are "quad_adaptive", "quad_fixed" and "ode".

tol=None means 1e-6 for adaptive quadrature and ODE. The optional third positional tolerance is retained. Fixed quadrature accepts n_points instead and rejects an explicit tolerance. Other keyword options are forwarded to the selected method; unsupported options raise TypeError rather than being silently ignored. See each named method for its numerical assumptions, diagnostics and differentiation semantics.

get_arclength_ode(u1=0.0, u2=1.0, tol=1e-06, *, atol=None, rtol=None, max_steps=4096, return_info=False)[source]#

Integrate speed with knot-aware Dopri5 and local error controls.

See get_arclength_quad_adaptive for geometry, signed interval and diagnostic conventions. Each unspecified atol/rtol defaults to tol. Local ODE controls do not guarantee the global length error. max_steps is a static workspace limit. ODE error_estimate is NaN and evaluations is -1: Diffrax exposes attempted step counts, not a global error estimate or exact RHS count. Scalar calls raise on failure.

get_arclength_quad_adaptive(u1=0.0, u2=1.0, tol=1e-06, *, atol=None, rtol=None, adjoint='direct', max_intervals=512, return_info=False)[source]#

Integrate speed using adaptive knot-aware Gauss-Kronrod quadrature.

Reversed limits give a signed integral and equal limits give zero. Requires real finite geometry, positive weights, in-domain limits and no interior curve discontinuities. Zero speed is allowed for length.

Parameters:
u1, u2float, optional

In-domain integration limits, defaulting to 0 and 1.

tolfloat, optional

Default for each unspecified tolerance (1e-6).

atol, rtolfloat, optional

Absolute/relative controls: target max(atol, rtol*abs(length)).

adjoint{“direct”, “leibniz”}, optional

Direct differentiates the accepted mesh; Leibniz integrates sensitivities with their own adaptive solve. A primal error estimate does not certify gradient accuracy.

max_intervalsint, optional

Static workspace limit, default 512.

return_infobool, optional

Return ArcLengthInfo with value/error/work/status instead of a scalar. Nonzero status reports invalid input or solver failure. Scalar calls raise on failure, including under JIT.

Notes

Normalization and endpoint grading improve rational-layer resolution, but extreme features can evade sampling or exhaust floating-point resolution. Error estimates are not certificates. At zero velocity AD selects a zero norm subgradient; collapsed length is not differentiable.

get_arclength_quad_fixed(u1=0.0, u2=1.0, n_points=41)[source]#

Compute the arc length of the NURBS curve over the parameter interval [u₁, u₂] using fixed-point numerical quadrature.

The arc length of a parametric curve C(u) = [x(u), y(u), z(u)]ᵀ is defined as

L(u₁, u₂) = ∫‖C’(u)‖ du,

where C’(u) = dC/du and ‖C’(u)‖ = √(x’(u)² + y’(u)² + z’(u)²) is the local curve speed.

This function evaluates the integral in Eq. (1) using a Clenshaw-Curtis quadrature rule with a prescribed number of nodes n_points. The integrand is evaluated at fixed quadrature points, making this method computationally cheaper than adaptive ODE integration but generally less accurate for rational B-splines.

Parameters:
u1float, optional

Lower bound of the parameter domain (default: 0.0).

u2float, optional

Upper bound of the parameter domain (default: 1.0).

n_pointsint, optional

Requested minimum number of quadrature points (default: 41). Rounded up to a rule with 4*k+1 nodes, with at least 5 nodes, as required by Quadax’s embedded Clenshaw-Curtis rule.

Returns:
Lfloat

Arc length of the curve segment C(u) for u ∈ [u₁, u₂].

get_binormal(u)[source]#

Evaluate the unit binormal vector along the curve for the given u-parameterization.

The binormal is defined as:

b(u) = (C’(u) x C’’(u)) / ||C’(u) x C’’(u)||

Parameters:
uscalar or ndarray (N,)

Parametric coordinates.

Returns:
binormalndarray (ndim, N)

Unit binormal vectors.

get_curvature(u)[source]#

Evaluate the curvature of the curve for the input u-parametrization

The definition of the curvature is given by equation 10.7 (Farin’s textbook)

Parameters:
uscalar or ndarray with shape (N,)

Scalar or array containing the u-parameter used to evaluate the curvature

Returns:
curvaturescalar or ndarray with shape (N, )

Scalar or array containing the curvature of the curve

get_derivative(u, order)[source]#

Evaluate the derivative of the curve for the input u-parametrization

Parameters:
uscalar or ndarray with shape (N,)

Scalar or array containing the u-parameter used to evaluate the curve

orderinteger

Order of the derivative

Returns:
dCndarray with shape (ndim, N)

Array containing the derivative of the desired order The first dimension of dC spans the (x,y,z) coordinates The second dimension of dC spans the u parametrization sample points

get_normal(u)[source]#

Evaluate the unit normal vector along the curve for the given u-parameterization.

For 2D or 3D curves, the normal is defined as:
  • 2D: n(u) = (-t_y, t_x)

  • 3D: n(u) = (C’(u) x (C’’(u) x C’(u))) / ||C’(u) x (C’’(u) x C’(u))||

Parameters:
uscalar or ndarray (N,)

Parametric coordinates.

Returns:
normalndarray (ndim, N)

Unit normal vectors.

get_tangent(u)[source]#

Evaluate the unit tangent vector along the curve for the given u-parameterization.

The tangent is defined as:

t(u) = C’(u) / ||C’(u)||

Parameters:
uscalar or ndarray (N,)

Parametric coordinates.

Returns:
tangentndarray (ndim, N)

Unit tangent vectors.

get_torsion(u)[source]#

Evaluate the torsion of the curve for the input u-parametrization

The definition of the torsion is given by equation 10.8 (Farin’s textbook)

Parameters:
uscalar or ndarray with shape (N,)

Scalar or array containing the u-parameter used to evaluate the torsion

Returns:
torsionscalar or ndarray with shape (N, )

Scalar or array containing the torsion of the curve

get_value(u)[source]#

Evaluate the coordinates of the curve for the input u parametrization

Parameters:
uscalar or ndarray with shape (N,)

Parameter used to evaluate the curve

Returns:
Cndarray with shape (ndim, N)

Array containing the coordinates of the curve The first dimension of C spans the (x,y,z) coordinates The second dimension of C spans the u parametrization sample points

ndim: int#
p: int#
plot(fig=None, ax=None, curve=True, control_points=True, frenet_serret=False, axis_off=False, ticks_off=False, rescale=True)[source]#

Create a plot and return the figure and axes handles

plot_control_points(fig, ax, linewidth=1.25, linestyle='-.', color='red', markersize=5, markerstyle='o')[source]#

Plot the control points of the NURBS curve

plot_curvature(fig=None, ax=None, color='black', linestyle='-')[source]#
plot_curve(fig, ax, linewidth=1.5, linestyle='-', color='black', u1=0.0, u2=1.0)[source]#

Plot the coordinates of the NURBS curve

plot_frenet_serret(fig, ax, frame_number=5, frame_scale=0.1)[source]#

Plot some Frenet-Serret reference frames along the NURBS curve

plot_torsion(fig=None, ax=None, color='black', linestyle='-')[source]#
project_points(Q_all, tol=1e-09, *, maxiter=100, samples_per_span=64, gtol=None, xtol=1e-12, ftol=1e-14)[source]#

Project query columns using sampled initialization and one local solve.

The knot-aware grid is evaluated once for the batch. Its nearest point starts a bounded Newton/line-search minimization on the actual knot domain. samples_per_span is a static interior sampling budget; strongly unequal positive weights add logarithmic endpoint coverage within that budget. Finite sampling cannot guarantee a global minimum.

tol now controls tangent-scaled spatial stationarity, with threshold tol * (1 + distance). gtol overrides it when supplied. The default 1e-9 preserves the old effective internal tolerance; the old public 1e-6 argument was ignored. xtol and ftol detect stagnation, which alone is never accepted as convergence. Nonconverged solves raise an error. Static options must be finite/nonnegative; the sampling budget is positive.

Inputs have shape (ndim,N); returned parameters have shape (N,). Geometry must be finite, with positive weights and continuous knots (interior multiplicity at most degree). Empty query batches are allowed.

Forward and reverse AD use the exact unregularized stationarity Hessian at a locally unique regular minimum with stable active bounds. Invalid sensitivities at collapsed geometry, weak bounds and nonsmooth knots are NaN. Local checks cannot certify global uniqueness. For the minimized squared-distance loss only, freezing the solved parameters also gives the envelope gradient; this does not apply to arbitrary downstream losses.

reparametrize_by_arclength(tol=1e-06, *, max_steps=512, steps_per_span=16, max_intervals=512)[source]#

Return a dense ODE map u_of_s and the total arc length.

Adaptive quadrature first computes each knot-span length. Independent reciprocal ODEs then integrate normalized parameter against normalized distance on each span. Dense interpolants give fast queries without quadrature or root finding. Exact span anchors prevent cumulative drift across knots; steps_per_span sets a minimum dense-output resolution.

This method requires a regular curve with positive speed, including one-sided endpoint limits. Sampled stationary points, flat spans, failed solves and nonmonotone sampled output are rejected explicitly. No epsilon is added to hide a reciprocal singularity. Regularity and monotonicity sampling are checks, not everywhere-valid proofs.

tol is the quadrature and local ODE control, not a global inverse- map or unit-speed error guarantee. Tighter controls may be needed for sensitivities. max_steps bounds dense storage per knot span.

The returned compiled callable accepts scalar/array distances in [0, total_length], preserves shape and supports JAX differentiation on regular curves. It is a geometry snapshot: rebuild after changes to control points, weights or knots. Keep construction inside a transform when differentiating with respect to the geometry.

reparametrize_by_coordinate(dim=0, tol=1e-09)[source]#

Construct a callable function that reparametrizes the NURBS curve by one of its coordinate components, returning the corresponding parameter values u(x).

Let the curve be defined parametrically as

C(u) = [C₀(u), C₁(u), …, Cₙ₋₁(u)]ᵀ, u ∈ [0, 1].

This function reparametrizes the curve using the coordinate C_dim(u) as the independent variable. For a given coordinate value x*, the corresponding parameter u* is obtained by solving

R(u) = C_dim(u) - x* = 0.

This equation is solved using a bounded Newton iteration implemented through optimistix.root_find, ensuring u* ∈ [0, 1]. The process is vectorized and JIT-compiled under JAX for efficient batch evaluation.

The resulting callable maps coordinate values x → u(x), providing the inverse parameterization where one coordinate (e.g. x) serves as the independent variable. The actual curve points can subsequently be obtained as C(u(x)) if desired.

The mapping is well-defined only if C_dim(u) is monotonic over [0, 1].

Parameters:
dimint, optional

Index of the coordinate used as independent variable. Default is 0 (the first coordinate component, typically x).

tolfloat, optional

Relative and absolute tolerance for the Newton solver (default: 1e-9).

Returns:
callable

A JAX-compiled, vectorized function handle u(x) that returns the parameter values corresponding to the specified coordinate values x, i.e.

u(x) = C_i⁻¹(x),

where C_i⁻¹ denotes the inverse mapping of the coordinate function C_i(u) over the domain [0, 1].

rescale_plot(fig, ax)[source]#

Adjust the aspect ratio of the figure

nurbspy.jax.nurbs_curve.binomial_coeff(n, k)[source]#

JAX-compatible binomial coefficient C(n, k) using the gamma function.

nurbspy.jax.nurbs_curve.compute_all_bspline_derivatives(P, p, U, u, up_to_order)[source]#

Compute all analytic derivatives of a polynomial B-spline curve up to a specified order.

This function evaluates the curve and its parametric derivatives using the analytic derivatives of the B-spline basis functions. For each derivative order k, the derivative of the curve is given by

C^(k)(u) = Σ_i P_i * d^k N_{i,p}(u) / du^k

Parameters:
Pndarray (ndim, n+1)

Control point coordinates.

pint

Degree of the B-spline.

Undarray (n+p+2,)

Knot vector.

undarray (Nu,)

Parametric evaluation points.

up_to_orderint

Maximum nonnegative derivative order. Orders above the degree are zero.

Returns:
bspline_derivativesndarray (up_to_order+1, ndim, Nu)

Derivatives of the B-spline curve, where bspline_derivatives[k, :, :] = d^k C(u) / du^k.

nurbspy.jax.nurbs_curve.compute_all_nurbs_derivatives(P, W, p, U, u, up_to_order)[source]#

Compute all analytic derivatives of a NURBS curve up to a specified order.

This function extends the polynomial B-spline derivative computation to rational NURBS curves by applying the quotient rule recursively, following Algorithm A4.2 from The NURBS Book (Piegl & Tiller, 2nd ed.):

Parameters:
Pndarray (ndim, n+1)

Control point coordinates.

Wndarray (n+1,)

Control point weights.

pint

Degree of the NURBS.

Undarray (n+p+2,)

Knot vector.

undarray (Nu,)

Parametric evaluation points.

up_to_orderint

Maximum nonnegative derivative order, which may exceed the degree.

Returns:
nurbs_derivativesndarray (up_to_order+1, ndim, Nu)

Derivatives of the NURBS curve

nurbspy.jax.nurbs_curve.compute_bspline_coordinates(P, p, U, u)[source]#

Evaluate the coordinates of a B-spline curve for a given parameter u.

This function computes the coordinates of a polynomial B-spline curve using the standard basis expansion (Equation 3.1 in The NURBS Book). The implementation corresponds to Algorithm A3.1.

Parameters:
Pndarray (ndim, n+1)

Array of control point coordinates. The first dimension spans spatial coordinates (x, y, z, …), and the second spans the control points along the curve (0, 1, …, n).

pint

Degree of the B-spline basis functions.

Undarray (r+1 = n + p + 2,)

Knot vector in the u-direction. The first and last entries typically have multiplicity p + 1 for a clamped spline.

uscalar or ndarray (N,)

Parametric coordinate(s) at which to evaluate the curve.

Returns:
Cndarray (ndim, N)

Coordinates of the evaluated B-spline curve points. The first dimension spans the spatial coordinates, and the second spans the parametric evaluation points u.

Notes

  • The computation is vectorized and uses matrix multiplication for efficiency.

  • For rational curves (NURBS), use compute_nurbs_coordinates instead.

nurbspy.jax.nurbs_curve.compute_nurbs_coordinates(P, W, p, U, u)[source]#

Evaluate the coordinates of a NURBS (Non-Uniform Rational B-Spline) curve for a given parameter u.

This function computes the coordinates of the NURBS curve in homogeneous space using the standard B-spline basis and the control point weights (Equation 4.5 in The NURBS Book), and then maps them back to ordinary space via the rational perspective division (Equation 1.16). The implementation corresponds to Algorithm A4.1 from The NURBS Book.

Parameters:
Pndarray (ndim, n+1)

Array of control point coordinates. The first dimension spans spatial coordinates (x, y, z, …), and the second spans the control points along the curve (0, 1, …, n).

Wndarray (n+1,)

Weights associated with each control point.

pint

Degree of the B-spline basis functions.

Undarray (r+1 = n + p + 2,)

Knot vector in the u-direction. The first and last entries typically have multiplicity p + 1 for a clamped spline.

uscalar or ndarray (N,)

Parametric coordinate(s) at which to evaluate the curve.

Returns:
Cndarray (ndim, N)

Coordinates of the evaluated curve points. The first dimension spans the spatial coordinates, and the second spans the parametric evaluation points u.

Notes

  • The computation is fully vectorized and uses matrix multiplication for efficiency.

  • The function supports arbitrary spatial dimensions.

nurbspy.jax.nurbs_curve.merge_nurbs_curves(nurbs_list)[source]#

Merge multiple NURBS curves into a single continuous curve with C⁰ continuity.

Parameters:
nurbs_listlist of NurbsCurve

List of NURBS curve instances to merge. All must have the same polynomial degree.

Returns:
mergedNurbsCurve

A new NURBS curve representing the concatenation of all input curves.

Notes

  • Each curve is mapped to a subinterval of [0, 1] with equal length.

  • Adjacent curves are connected with multiplicity p + 1 (C⁰ continuity).

  • A small epsilon offset is applied at internal joins to avoid Gmsh issues related to repeated knots with multiplicity exactly equal to degree.