【问题标题】:How to redistribute points evenly over a curve如何在曲线上均匀地重新分布点
【发布时间】:2017-03-22 11:34:23
【问题描述】:

我有一些由 XYZ 笛卡尔点列表组成的 3 维任意曲线。点分布不均匀(有时间因素)。如何用给定数量的应该构成曲线的点“重建”曲线。我看到这是在 3D 建模程序中完成的,所以我很确定这是可能的,我只是不知道如何。

根据答案,我在 python 中需要它,所以我开始努力将 interparc 转换为 python。我得到了线性插值。它可能效率低下并且有冗余,但它可能对某人有用http://pastebin.com/L9NFvJyA

【问题讨论】:

  • 那么,您已经计算了最佳拟合曲线,现在您只想使用点来显示它吗?或者你还需要这样做吗?还是两者都没有?
  • 不,我有定义曲线的点,我需要沿着这条曲线均匀分布这些点。不过,“曲线”没有计算出来,它只是一个点数据集
  • 如果您有“定义”曲线的点,您应该能够计算曲线。否则我不太确定您的意思是“重新分配”。
  • 我添加了一张图片来显示我在说什么。点沿曲线分布不均匀
  • 图片告诉我为什么你认为你应该能够做到这一点而不需要计算任何东西。但是更多的点真的没有什么区别!您如何绝对确定地知道任意两点之间的值,即使它们仅相隔一个很小的 ​​epsilon?您仍然需要使用某种回归,或者只取两个相邻点的平均值来找到更多可以选择使用或不使用的值。 en.wikipedia.org/wiki/Regression_analysis#Nonlinear_regression

标签: python math 3d


【解决方案1】:

我会使用interparc,这是我的一个工具,旨在做到这一点。它通过 2 维或更多维的一般空间曲线拟合样条曲线,然后选择沿该曲线的距离相等的点。在三次样条的情况下,解决方案使用 odesolver 来执行必须是数值积分的操作,因此它有点慢,但它仍然相当快。在许多情况下,一个简单的线性插值(我在这里使用)就足够了,而且速度非常快。

曲线可能是完全一般的,甚至与自身相交。我将举一个 3-d 空间曲线的简单示例:

t = linspace(0,1,500).^3;
x = sin(2*pi*t);
y = sin(pi*t);
z = cos(3*x + y);
plot3(x,y,z,'o')
grid on
box on
view(-9,12)

xyzi = interparc(100,x,y,z,'lin');
plot3(xyzi(:,1),xyzi(:,2),xyzi(:,3),'o')
box on
grid on
view(-9,12)

【讨论】:

  • 哇,这看起来很有希望,曲线不需要关闭吗?
  • 曲线可以完全通用,不需要闭合。不过,我已经提供了这种功能,以防第一点和最后一点相同。
  • 算法写下来了吗?我不使用 matlab,很难解析正在发生的事情
【解决方案2】:

首先,感谢 John D'Errico 先生的 interparc。多么棒的工作!

我也遇到过这个问题,但不熟悉 MATLAB 引擎 API。鉴于此,我尝试将部分 interparc Matlab 代码转换为 Python(仅包括线性插值,因为它足以解决我的问题)。

这是我的代码;希望它可以帮助所有寻求类似东西的pythonics:

import numpy as np

def interpcurve(N,pX,pY):
#equally spaced in arclength
N=np.transpose(np.linspace(0,1,N))

#how many points will be uniformly interpolated?
nt=N.size

#number of points on the curve
n=pX.size
pxy=np.array((pX,pY)).T
p1=pxy[0,:]
pend=pxy[-1,:]
last_segment= np.linalg.norm(np.subtract(p1,pend))
epsilon= 10*np.finfo(float).eps

#IF the two end points are not close enough lets close the curve
if last_segment > epsilon*np.linalg.norm(np.amax(abs(pxy),axis=0)):
    pxy=np.vstack((pxy,p1))
    nt = nt + 1
else:
    print('Contour already closed')

pt=np.zeros((nt,2))

#Compute the chordal arclength of each segment.
chordlen = (np.sum(np.diff(pxy,axis=0)**2,axis=1))**(1/2)
#Normalize the arclengths to a unit total
chordlen = chordlen/np.sum(chordlen)
#cumulative arclength
cumarc = np.append(0,np.cumsum(chordlen))

tbins= np.digitize(N,cumarc) # bin index in which each N is in

#catch any problems at the ends
tbins[np.where(tbins<=0 | (N<=0))]=1
tbins[np.where(tbins >= n | (N >= 1))] = n - 1      

s = np.divide((N - cumarc[tbins]),chordlen[tbins-1])
pt = pxy[tbins,:] + np.multiply((pxy[tbins,:] - pxy[tbins-1,:]),(np.vstack([s]*2)).T)

return pt 

【讨论】:

  • 我很快就会上传,但我和一些学生一起研究了这个,并提出了完整的代码。但是,是的,我认为这对很多人都很有用
  • 我不得不改变你的“|” np.bitwise_or 的两个“tbins[np.where...]”行中的运算符;否则它们不会按照您的预期运行(我认为)。我还注释掉了曲线闭合块,因为它为我的非闭合曲线应用程序创建了奇怪的行为。否则,干得好。我希望有人将完整的 interparc 代码 Python 化,因为它非常有用。
  • 除了之前的评论,在摆脱曲线闭合块后,我不得不像这样更改以下行: s = np.divide((N - cumarc[tbins-1]),chordlen[ tbins-1]) pt = pxy[tbins-1,:] + np.multiply((pxy[tbins,:] - pxy[tbins-1,:]),(np.vstack([s]*ndim)) .T)。现在,这给出了与用于线性插值的原始 Matlab 函数相同的结果。
  • 这对我来说效果非常好,但要求我在运行 interpcurve 之前将输入标准化为等量级。只是为未来的用户提个醒。
【解决方案3】:

你的“曲线”是一堆连接一堆点的线段。每个线段都有一个长度;曲线的总长度是这些线段长度的总和。

所以计算d = totalCurveLength / (numberOfPoints - 1),并将曲线分割成(numberOfPoints - 1)长度为d的块。

【讨论】:

    【解决方案4】:

    不确定我是否在关注,但不是存储实际数据,而是存储点到点的增量,然后从增量重建曲线,这样就不会有任何空白点?但是,这会改变曲线的形状。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-24
      • 1970-01-01
      相关资源
      最近更新 更多