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

如何在Matplotlib中实现沿轨迹方向等距偏移的平行复合线型

Matplotlib 任意轨迹等距平行双线实现方案

核心是通过轨迹法向计算+转角交点修正,实现全程等距、偏移方向始终沿轨迹右侧的平行线条,避免固定x/y偏移、默认path_effects静态偏移带来的转角间距不均、方向不匹配问题。


实现逻辑

  • 逐段计算原始轨迹的切向向量,顺时针旋转90°得到轨迹前进方向的右侧法向向量,归一化后乘以设定偏移距离,得到每段线段的偏移基准
  • 对相邻两段的偏移线段求交点,作为转角处的偏移顶点,替代原始点直接偏移的结果,解决转角处平行间距收窄的问题
  • 所有点计算完成后得到和原始轨迹全程垂直等距的平行轨迹,可按需设置实线、虚线等样式

实现代码

import matplotlib.pyplot as plt
import numpy as np

def generate_right_offset_curve(x, y, offset_dist):
    """
    生成原始轨迹右侧固定垂直距离的等距平行轨迹
    参数:
        x, y: 原始轨迹的坐标数组
        offset_dist: 平行线与原轨迹的垂直距离,单位与轨迹坐标一致
    返回:
        offset_x, offset_y: 等距平行轨迹的坐标数组
    """
    x = np.asarray(x, dtype=np.float64)
    y = np.asarray(y, dtype=np.float64)
    point_num = len(x)
    offset_x = np.zeros(point_num)
    offset_y = np.zeros(point_num)

    # 计算每段线段的切向与右侧法向
    seg_dx = np.diff(x)
    seg_dy = np.diff(y)
    seg_len = np.hypot(seg_dx, seg_dy)
    # 切向(dx, dy)顺时针转90°得到右侧法向(dy, -dx),做归一化
    norm_nx = seg_dy / seg_len
    norm_ny = -seg_dx / seg_len

    # 计算起点偏移位置
    offset_x[0] = x[0] + norm_nx[0] * offset_dist
    offset_y[0] = y[0] + norm_ny[0] * offset_dist

    # 逐点计算中间转角的交点位置,保证转角等距
    for i in range(1, point_num - 1):
        # 相邻两段各自的偏移线段端点
        l1_p1 = (x[i-1] + norm_nx[i-1]*offset_dist, y[i-1] + norm_ny[i-1]*offset_dist)
        l1_p2 = (x[i] + norm_nx[i-1]*offset_dist, y[i] + norm_ny[i-1]*offset_dist)
        l2_p1 = (x[i] + norm_nx[i]*offset_dist, y[i] + norm_ny[i]*offset_dist)
        l2_p2 = (x[i+1] + norm_nx[i]*offset_dist, y[i+1] + norm_ny[i]*offset_dist)

        # 求解两线段交点作为转角偏移点
        x1, y1 = l1_p1
        x2, y2 = l1_p2
        x3, y3 = l2_p1
        x4, y4 = l2_p2
        denom = (x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)
        t = ((x1 - x3)*(y3 - y4) - (y1 - y3)*(x3 - x4)) / denom
        offset_x[i] = x1 + t*(x2 - x1)
        offset_y[i] = y1 + t*(y2 - y1)

    # 计算终点偏移位置
    offset_x[-1] = x[-1] + norm_nx[-1] * offset_dist
    offset_y[-1] = y[-1] + norm_ny[-1] * offset_dist

    return offset_x, offset_y


# 用法示例
if __name__ == "__main__":
    fig, (ax1, ax2) = plt.subplots(1, 2, dpi=100, figsize=(10, 4))

    # 测试1:带直角拐点的简单轨迹
    X_simple = np.array([0, 1, 1, 0, 0.5])
    Z_simple = np.array([1, 1, 0, 0, 0.5])
    offset = 0.03
    ox_simple, oz_simple = generate_right_offset_curve(X_simple, Z_simple, offset)
    ax1.plot(X_simple, Z_simple, 'r', linewidth=2)
    ax1.plot(ox_simple, oz_simple, 'r--', linewidth=2)
    ax1.set_title('带拐点简单轨迹测试')
    ax1.set_aspect('equal')  # 必须开启等比例坐标轴,否则视觉间距会变形

    # 测试2:复杂螺旋曲线轨迹
    t = np.linspace(0, 4*np.pi, 200)
    X_complex = t * np.cos(t) * 0.2
    Z_complex = t * np.sin(t) * 0.2
    ox_complex, oz_complex = generate_right_offset_curve(X_complex, Z_complex, offset_dist=0.15)
    ax2.plot(X_complex, Z_complex, 'b', linewidth=2)
    ax2.plot(ox_complex, oz_complex, 'b--', linewidth=2)
    ax2.set_title('复杂曲线轨迹测试')
    ax2.set_aspect('equal')

    plt.tight_layout()
    plt.show()

使用注意事项

  • 绘制时必须设置ax.set_aspect('equal')保证x、y轴缩放比例一致,否则会出现法向计算偏差、视觉间距不等的问题
  • 该方法对任意折线、采样密度足够的连续曲线都生效,平行间距全程恒定,转角无收窄问题,虚线始终位于轨迹前进方向的右侧
  • 绘制闭合轨迹时,只需将轨迹首尾点设置为同一坐标,函数可自动处理闭合处的转角衔接
  • 不需要依赖matplotlib的path_effects静态偏移能力,偏移方向完全随轨迹走向动态计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:30:55