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

如何用Python(优先SciPy)生成指定曲率与首尾切线的三次样条?

实现带切线约束与曲率限制的三次样条曲线(SciPy版)

嘿,我来帮你搞定这个带约束的三次样条需求!首先得提个关键注意点:你给的路点里x坐标有重复的情况(比如前两个点x都是-18),直接用x作为自变量插值会出问题,所以咱们得用参数化样条——用一个参数t遍历每个路点,分别对x(t)和y(t)做插值,这样就能完美处理非单调的路径了。

下面是完整的可运行代码,包含切线约束、曲率计算和可视化:

import numpy as np
from scipy.interpolate import CubicSpline
import matplotlib.pyplot as plt

# 给定的路点数组
waypoints = np.array([
    [-18., -20.], [-18., 18.], [-14., 18.], [-14., -18.], [-10., -18.],
    [-10., 18.], [ -6., 18.], [ -6., -18.], [ -2., -18.], [ -2., 18.],
    [ 2., 18.], [ 2., -18.], [ 6., -18.], [ 6., 18.], [ 10., 18.],
    [ 10., -18.], [ 14., -18.], [ 14., 18.], [ 18., 18.], [ 18., -20.]
])

# 1. 设置参数化变量t,每个路点对应一个t值(从0到19)
t = np.arange(len(waypoints))
x_coords = waypoints[:, 0]
y_coords = waypoints[:, 1]

# 2. 定义起点和终点的切线约束(一阶导数)
# 起点切线:沿第一个点到第二个点的方向
dx_start = x_coords[1] - x_coords[0]
dy_start = y_coords[1] - y_coords[0]
# 终点切线:沿倒数第二个点到最后一个点的方向
dx_end = x_coords[-1] - x_coords[-2]
dy_end = y_coords[-1] - y_coords[-2]

# 3. 创建三次样条,指定边界导数约束
# 对x(t)和y(t)分别构建样条
cs_x = CubicSpline(t, x_coords, bc_type=((1, dx_start), (1, dx_end)))
cs_y = CubicSpline(t, y_coords, bc_type=((1, dy_start), (1, dy_end)))

# 4. 生成密集采样点用于绘制曲线
t_dense = np.linspace(0, t[-1], 1000)
x_spline = cs_x(t_dense)
y_spline = cs_y(t_dense)

# 5. 计算并检查曲率
# 求一阶、二阶导数
x1 = cs_x(t_dense, 1)  # x'(t)
x2 = cs_x(t_dense, 2)  # x''(t)
y1 = cs_y(t_dense, 1)  # y'(t)
y2 = cs_y(t_dense, 2)  # y''(t)

# 参数化曲线的曲率公式
curvature = np.abs(x1 * y2 - x2 * y1) / (x1**2 + y1**2)**(1.5)

# 设置你的曲率阈值,这里示例用0.1,可按需修改
curvature_threshold = 0.1
max_curv = np.max(curvature)

print(f"曲线最大曲率: {max_curv:.4f}")
if max_curv > curvature_threshold:
    print(f"⚠️ 警告:最大曲率超过设定阈值 {curvature_threshold}")
else:
    print(f"✅ 曲率符合要求,未超过阈值 {curvature_threshold}")

# 6. 可视化结果
plt.figure(figsize=(10, 8))
plt.scatter(x_coords, y_coords, color='#ff4444', s=60, label='原始路点')
plt.plot(x_spline, y_spline, color='#2196f3', linewidth=2, label='三次样条曲线')
plt.xlabel('X 坐标')
plt.ylabel('Y 坐标')
plt.title('带切线约束的参数化三次样条曲线')
plt.legend()
plt.grid(True, linestyle='--', alpha=0.7)
plt.axis('equal')  # 保持坐标轴比例,避免曲线变形
plt.show()

关键部分解释

  1. 参数化样条:
    因为你的路点x坐标不是严格单调的(比如前两个点x都是-18),直接用x作为自变量插值y会触发SciPy的错误。用参数t来分别拟合x(t)和y(t),就能轻松处理这种上下往复的路径。

  2. 切线约束实现:
    通过CubicSpline的bc_type参数,我们指定了起点和终点的一阶导数(切线方向)。这里直接用相邻路点的差值作为导数,完全符合你要求的“起点切线经过起点和下一个点,终点切线经过前一个点和终点”的约束。

  3. 曲率计算与检查:
    用参数化曲线的曲率公式计算每一点的曲率,然后和你设定的阈值对比。如果曲率超标,你可以考虑:

    • 在曲率过大的路段增加过渡路点,让曲线更平滑;
    • 调整边界导数的大小(如果允许的话);
    • 改用B样条并调整节点间距,但三次样条已经足够满足大多数平滑需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 09:47:54