You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对B样条曲线做弧长重参数化并生成按长度参数化的新B样条?

B样条曲线弧长参数化近似实现方案

B样条不存在解析的弧长参数化表达式,可通过数值近似方案实现需求,误差可通过采样密度灵活控制。


实现步骤

  • 高密度采样原始曲线,计算各采样点的累计弧长,构建原始参数t到弧长s的映射表
  • 通过线性插值构建逆映射:输入归一化弧长比例(01,对应总长度0%100%),输出对应原始参数t
  • 采样足够多的均匀弧长点,拟合新的二次B样条,得到近似弧长参数化的新曲线

完整代码实现

from splipy import Curve, BSplineBasis
from splipy.utils import interpolate_curve
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

ORDER = 3  # 二次B样条
cp = np.array([[0,0,0], [0, 1,0], [0,2,0], [0,3,0], [1,3,0],[2,3,0], [3,3,0]])
num_cp = cp.shape[0]

# 构建原始曲线
knot = np.array([0. , 0. , 0. , 0.2, 0.4, 0.6, 0.8, 1. , 1. , 1. ])
basis = BSplineBasis(order=ORDER, knots=knot, periodic=-1)
curve = Curve(basis=basis, controlpoints=cp, rational=False)

# -------------------------- 弧长参数化核心逻辑 --------------------------
# 1. 高密度采样计算弧长映射表,采样点数越高精度越高
SAMPLE_DENSITY = 1000
t_sample = np.linspace(0, 1, SAMPLE_DENSITY)
pts_sample = curve(t_sample)
# 计算相邻点距离和累计弧长
delta_l = np.linalg.norm(np.diff(pts_sample, axis=0), axis=1)
cum_length = np.concatenate([[0], np.cumsum(delta_l)])
total_length = cum_length[-1]
# 归一化累计弧长到0~1区间
cum_length_norm = cum_length / total_length

# 2. 逆映射函数:输入归一化弧长比例s_norm(0~1),返回对应原始参数t
def s_to_t(s_norm):
    # 找到s_norm所在的区间位置
    idx = np.searchsorted(cum_length_norm, s_norm, side='right') - 1
    if idx >= len(cum_length_norm) - 1:
        return t_sample[-1]
    # 线性插值计算精确t值
    alpha = (s_norm - cum_length_norm[idx]) / (cum_length_norm[idx+1] - cum_length_norm[idx])
    return t_sample[idx] + alpha * (t_sample[idx+1] - t_sample[idx])

# 3. 拟合新的弧长参数化B样条
# 采样足够多的均匀弧长点作为拟合依据
NUM_FIT_POINTS = 100
s_fit = np.linspace(0, 1, NUM_FIT_POINTS)
t_fit = np.vectorize(s_to_t)(s_fit)
pts_fit = curve(t_fit)
# 拟合二次B样条
arc_param_curve = interpolate_curve(pts_fit, order=ORDER)

# -------------------------- 效果验证 --------------------------
# 对新曲线用均匀参数采样,验证点分布均匀
u_new = np.linspace(0, 1, 10)
points_10_even = arc_param_curve(u_new)

# 绘图对比
fig = plt.figure(figsize=(12,6))
ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122, projection='3d')

# 左图:原始曲线不均匀采样
t_origin = np.linspace(0,1,100)
pts_origin = curve(t_origin)
x,y,z = pts_origin.T
ax1.plot(x,y,z,'b-')
x,y,z = curve(np.linspace(0,1,10)).T
ax1.plot(x,y,z,'r*')
ax1.set_title('原始曲线均匀参数采样')

# 右图:新曲线均匀参数采样
t_new = np.linspace(0,1,100)
pts_new = arc_param_curve(t_new)
x,y,z = pts_new.T
ax2.plot(x,y,z,'g-')
x,y,z = points_10_even.T
ax2.plot(x,y,z,'r*')
ax2.set_title('弧长参数化曲线均匀参数采样')

plt.show()

效果说明

原始曲线的均匀参数采样点分布不均,弯曲处点更密集:
不均匀采样示例
新生成的arc_param_curve输入均匀t值即可得到沿弧长均匀分布的点,精度可通过调整SAMPLE_DENSITY和NUM_FIT_POINTS参数控制,数值越高近似效果越好。


内容的提问来源于stack exchange,提问作者Will Sni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 11:27:04