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

如何基于测量点集计算曲线的平行等距线?

问题:生成与离散曲线等距的平行点集

我有一组(x,y)测量点,想要基于原曲线计算出一组与原曲线保持等距的平行点集,但多次调整计算逻辑后结果都不符合预期——每个点应与原曲线保持完全一致的距离。

之前的尝试及问题

例1:距离不一致

垂直段的平行距偏大,水平/曲线段的平行距偏小:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv('data.csv')
print(df.columns)
print(df.head())

df_s = df[["TVD","VS"]].sort_values(axis=0, by='TVD', ascending=True).reset_index(drop=True)
df_s['TVD'] = df_s['TVD']*-1
print(df.info())
# df_s.to_csv('filt.csv')

print(df_s.head())
# Define the original curved line

df_s = df_s[df_s['TVD']>-5000]
y = df_s['TVD']
x = df_s['VS']

# Define the distance between the original and parallel lines
distance = 50

# Calculate the offset for the parallel line
dx = np.gradient(x)
dy = np.gradient(y)
ds = np.sqrt(dx**2 + dy**2)
dxn = dx / ds
dyn = dy / ds
x_offset = distance * dyn
y_offset = -distance * dxn

# Calculate the new curved line
x_new = x + x_offset
y_new = y + y_offset

# Plot the original and parallel lines
plt.plot(x, y, label='Original')
plt.plot(x_new, y_new, label='Parallel')
plt.legend()
plt.show()

例2:曲线交叉

平行曲线与原曲线出现交叉:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv('data.csv')
print(df.columns)
print(df.head())

df_s = df[["TVD","VS"]].sort_values(axis=0, by='TVD', ascending=True).reset_index(drop=True)
df_s['TVD'] = df_s['TVD']*-1
print(df.info())
# df_s.to_csv('filt.csv')

print(df_s.head())
# Define the original curved line

df_s = df_s[df_s['TVD']>-5000]
y = df_s['TVD']
x = df_s['VS']


# Define the distance between the original and parallel lines
distance = 50

# Calculate the inclination angle at each point along the original line
dx = np.gradient(x)
dy = np.gradient(y)
inclination = np.arctan2(dy, dx)

# Calculate the adjusted distance for the parallel line
adjusted_distance = distance * np.cos(inclination)

# Calculate the offset for the parallel line
x_offset = adjusted_distance * np.sin(inclination)
y_offset = -adjusted_distance * np.cos(inclination)

# Calculate the new curved line
x_new = x + x_offset
y_new = y + y_offset

# Plot the original and parallel lines
plt.plot(x, y, label='Original')
# plt.plot(x_new, y_new, label='Parallel')
plt.legend()
plt.show()

期望效果

需要实现类似手绘的等距平行曲线,确保全段距离一致。


问题分析

  1. 例1错误原因:直接使用np.gradient计算离散点的梯度,受点的采样密度影响极大——垂直段点密集时,梯度计算出的dy偏小,导致法线方向偏移量计算错误;同时离散点直接偏移会忽略曲线的整体曲率,局部偏移方向不一致,造成距离不均。
  2. 例2错误原因:错误地用cos(inclination)调整偏移距离,偏离了法线偏移的核心逻辑,导致偏移方向和幅度完全错误,最终出现曲线交叉。

解决方案:B样条拟合+法线偏移

通过拟合连续的B样条曲线,准确计算每个点的法线方向,再进行偏移,能保证全段距离一致,避免交叉问题。

完整代码

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.interpolate import splprep, splev

# 读取并预处理数据
df = pd.read_csv('data.csv')
df_s = df[["TVD","VS"]].sort_values(by='TVD', ascending=True).reset_index(drop=True)
df_s['TVD'] = df_s['TVD'] * -1
df_s = df_s[df_s['TVD'] > -5000]
y = df_s['TVD'].values
x = df_s['VS'].values

# 设定偏移距离
offset_distance = 50

# 1. 弧长参数化拟合B样条曲线,解决采样不均问题
# 计算累积弧长
dx = np.diff(x)
dy = np.diff(y)
segment_lengths = np.sqrt(dx**2 + dy**2)
cumulative_length = np.cumsum(np.insert(segment_lengths, 0, 0))
normalized_t = cumulative_length / cumulative_length[-1]

# 拟合三次B样条(k=3),s=0强制通过所有原始点,s>0可平滑噪声
tck, u = splprep([x, y], u=normalized_t, k=3, s=0)

# 生成更密集的拟合点,提升偏移精度
u_dense = np.linspace(0, 1, len(x)*10)
x_fit, y_fit = splev(u_dense, tck)

# 2. 计算拟合曲线的切线向量
dx_dt, dy_dt = splev(u_dense, tck, der=1)
tangent_magnitude = np.sqrt(dx_dt**2 + dy_dt**2)
# 归一化切线向量
tx = dx_dt / tangent_magnitude
ty = dy_dt / tangent_magnitude

# 3. 计算法线向量(逆时针转90度,如需顺时针偏移则改为nx=ty, ny=-tx)
nx = -ty
ny = tx

# 4. 计算偏移后的点集
x_offset = x_fit + offset_distance * nx
y_offset = y_fit + offset_distance * ny

# 可视化结果
plt.figure(figsize=(10, 8))
plt.plot(x, y, 'o', markersize=4, label='原始测量点')
plt.plot(x_fit, y_fit, label='拟合原曲线')
plt.plot(x_offset, y_offset, label=f'等距偏移曲线(距离={offset_distance})')
plt.legend()
plt.xlabel('VS')
plt.ylabel('TVD')
plt.grid(alpha=0.3)
plt.show()

代码说明

  • 弧长参数化:保证样条在曲线的不同部分均匀采样,避免密集点处梯度计算误差。
  • B样条拟合:将离散点转换为连续曲线,能准确计算任意点的切线和法线方向。
  • 法线偏移:基于切线方向计算垂直的法线向量,确保偏移方向始终与曲线垂直,保证距离一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 10:32:03