Source code for torx.analysis.bspline_m
"""General B-spline basis evaluation utilities."""
import numpy as np
from numba import njit
[docs]
@njit(cache=True)
def bspline_basis_and_deriv1(u, k, t):
"""
Return (N, dN) of length k+1: B-spline basis and 1st derivatives at u.
k is the degree, t is the knot vector.
N[r] = B_{i-k+r}^k(u), dN[r] = dB_{i-k+r}^k/du, where i is the knot span.
Also returns i so callers can map basis values to spline coefficients.
"""
n = len(t) - k - 1
# Find knot span: largest i s.t. t[i] <= u < t[i+1]
if u >= t[n]:
i = n - 1
elif u <= t[k]:
i = k
else:
lo, hi = k, n
mid = (lo + hi) // 2
while u < t[mid] or u >= t[mid + 1]:
if u < t[mid]:
hi = mid
else:
lo = mid
mid = (lo + hi) // 2
i = mid
N = np.zeros(k + 1)
N[0] = 1.0
left = np.empty(k + 1)
right = np.empty(k + 1)
for j in range(1, k + 1):
left[j] = u - t[i + 1 - j]
right[j] = t[i + j] - u
saved = 0.0
for r in range(j):
denom = right[r + 1] + left[j - r]
temp = N[r] / denom if denom != 0.0 else 0.0
N[r] = saved + right[r + 1] * temp
saved = left[j - r] * temp
N[j] = saved
# Degree-(k-1) basis for derivative formula
Nm1 = np.zeros(k)
Nm1[0] = 1.0
for j in range(1, k):
left[j] = u - t[i + 1 - j]
right[j] = t[i + j] - u
saved = 0.0
for r in range(j):
denom = right[r + 1] + left[j - r]
temp = Nm1[r] / denom if denom != 0.0 else 0.0
Nm1[r] = saved + right[r + 1] * temp
saved = left[j - r] * temp
Nm1[j] = saved
dN = np.zeros(k + 1)
for r in range(k + 1):
lv = 0.0
if r > 0:
d = t[i + r] - t[i - k + r]
if d != 0.0:
lv = k * Nm1[r - 1] / d
rv = 0.0
if r < k:
d = t[i + r + 1] - t[i - k + r + 1]
if d != 0.0:
rv = k * Nm1[r] / d
dN[r] = lv - rv
return N, dN, i