1. 自由曲面基础参数化建模
任务说明
本案例使用非均匀有理B样条(NURBS)方法建立自由曲面模型。给定一张曲面的控制点网格、各方向节点向量及权重,通过NURBS曲面求值公式计算曲面上任意参数坐标(u,v)处的三维坐标点,并输出曲面在若干采样点处的坐标值,为后续自由曲面光学设计提供基础参数化模型。
NURBS曲面数学定义
一张p×q次NURBS曲面定义为:
S(u,v) = Σᵢ₌₀ⁿ Σⱼ₌₀ᵐ Nᵢ,ₚ(u) Nⱼ,𝒒(v) wᵢ,ⱼ Pᵢ,ⱼ / Σᵢ₌₀ⁿ Σⱼ₌₀ᵐ Nᵢ,ₚ(u) Nⱼ,𝒒(v) wᵢ,ⱼ
其中Pᵢ,ⱼ为控制点(三维坐标),wᵢ,ⱼ为对应权重,Nᵢ,ₚ(u)为定义在节点向量U上的B样条基函数。本案例实现完整的NURBS曲面求值:包括B样条基函数递归计算、节点向量构建、有理加权求值,并提供一个4×4控制点网格的曲面实例进行验证。
代码实现
import numpy as np
def find_span(n, p, u, U):
"""找到参数u所在节点区间下标(针对非均匀节点向量)"""
if u >= U[n+1]:
return n
if u <= U[p]:
return p
low, high = p, n+1
mid = (low + high) // 2
while (u < U[mid] or u >= U[mid+1]) and low < high:
if u < U[mid]:
high = mid
else:
low = mid
mid = (low + high) // 2
return mid
def basis_funcs(i, u, p, U):
"""计算第i个p次B样条基函数在u处的值N[i-p]...N[i]"""
N = np.zeros(p+1)
N[0] = 1.0
left = np.zeros(p+1)
right = np.zeros(p+1)
for j in range(1, p+1):
left[j] = u - U[i+1-j]
right[j] = U[i+j] - u
saved = 0.0
for r in range(j):
temp = N[r] / (right[r+1] + left[j-r])
N[r] = saved + right[r+1] * temp
saved = left[j-r] * temp
N[j] = saved
return N
def nurbs_surface_point(n, p, U, m, q, V, P, W, u, v):
"""计算NURBS曲面上参数(u,v)处的点坐标
参数:
n, p, U: u方向控制点数量-1、次数、节点向量
m, q, V: v方向控制点数量-1、次数、节点向量
P: 控制点数组,形状(n+1, m+1, 3)
W: 权重数组,形状(n+1, m+1)
u, v: 曲面参数坐标
返回:
曲面上的三维点 (x, y, z)
"""
# u方向基函数
iu = find_span(n, p, u, U)
Nu = basis_funcs(iu, u, p, U)
# v方向基函数
iv = find_span(m, q, v, V)
Nv = basis_funcs(iv, v, q, V)
# 有理加权求和
S = np.zeros(3)
w_sum = 0.0
for k in range(p+1):
for l in range(q+1):
i = iu - p + k
j = iv - q + l
weight = Nu[k] * Nv[l] * W[i][j]
S += weight * P[i][j]
w_sum += weight
return S / w_sum
def uniform_knot_vector(n, p):
"""生成均匀 clamped 节点向量(首尾重复p+1次)"""
m = n + p + 1
U = np.zeros(m+1)
for i in range(m+1):
if i <= p:
U[i] = 0.0
elif i >= m - p:
U[i] = 1.0
else:
U[i] = (i - p) / (m - 2*p)
return U
# ========== 实例:4x4控制点网格,3x3次NURBS曲面 ==========
n, p = 3, 3 # u方向:4个控制点,3次
m, q = 3, 3 # v方向:4个控制点,3次
# 生成均匀clamped节点向量
U = uniform_knot_vector(n, p)
V = uniform_knot_vector(m, q)
# 定义控制点:4x4网格,z坐标构成一个凸曲面形状
P = np.zeros((4, 4, 3))
for i in range(4):
for j in range(4):
P[i][j][0] = i * 10.0 # x: 0,10,20,30
P[i][j][1] = j * 10.0 # y: 0,10,20,30
# z: 边缘低、中心高的自由曲面形状
P[i][j][2] = 5.0 * (1 - abs(i-1.5)/1.5) * (1 - abs(j-1.5)/1.5) + 2.0
# 定义权重:全部为1.0(退化为B样条曲面)
W = np.ones((4, 4))
# 采样参数网格(u,v ∈ [0,1])
print("NURBS曲面采样点坐标(u,v → x,y,z):")
for u in [0.0, 0.33, 0.67, 1.0]:
for v in [0.0, 0.33, 0.67, 1.0]:
pt = nurbs_surface_point(n, p, U, m, q, V, P, W, u, v)
print(f"u={u:.2f}, v={v:.2f} → ({pt[0]:.4f}, {pt[1]:.4f}, {pt[2]:.4f})")
落地与验证
运行方式:将代码保存为nurbs_surface.py,在装有NumPy的Python环境中执行python nurbs_surface.py。
验证方法:观察输出结果,应满足以下判定标准:
- 曲面四角点(u=0/1, v=0/1)处坐标与控制点网格四角坐标完全一致,即(0,0,2.0)、(30,0,2.0)、(0,30,2.0)、(30,30,2.0)——因为clamped节点向量保证NURBS曲面插值边界控制点;
- 曲面中心(u=0.5, v=0.5)处z坐标应接近控制点中心高度(约7.0),体现曲面凸起形状;
- 所有输出点的x坐标在[0,30]区间、y坐标在[0,30]区间内单调分布。
若输出满足上述条件,说明NURBS曲面参数化建模实现正确,该模型可作为后续自由曲面光学设计的基底曲面。