2013-08-15 3 views
2

У меня есть произвольная кривая в трех измерениях, состоящая из списка декартовых точек XYZ. Точки распределены неравномерно (это фактор времени). Как я могу «перестроить» кривую с заданным количеством точек, которые должны составлять кривую. Я вижу это в программах 3D-моделирования, поэтому я уверен, что это возможно, я просто не знаю, как это сделать.Как распределить точки равномерно по кривой

enter image description here

На основании ответа, я нуждался в Python, так что я начал работать, чтобы преобразовать interparc в питона. Я дошел до линейной интерполяции. Вероятно, это неэффективно и имеет избыточность, но, возможно, это будет полезно кому-то. http://pastebin.com/L9NFvJyA

+0

Итак, вы уже рассчитали наилучшую длину кривой, и теперь вы просто хотите показать ее с помощью точек? Или вам все еще нужно это делать? Или нет? – vroomfondel

+0

Нет, у меня есть точки, которые определяют кривую, и мне нужно равномерно распределить точки вдоль этой кривой. «Кривая» не рассчитана, хотя ее просто набор данных точек – user1938107

+0

Если у вас есть точки, которые «определяют» кривую, вы должны иметь возможность рассчитать кривую. Я не совсем уверен, что вы подразумеваете под «перераспределением». – vroomfondel

ответ

6

Я бы использовал interparc, инструмент, предназначенный для этого. Он подходит для сплайна через общую пространственную кривую в 2 или более измерениях, затем выбирает точки, которые равномерно распределены по расстоянию вдоль этой кривой. В случае кубического сплайна в решении используется вспомогательный инструмент для выполнения численного интегрирования, поэтому он немного медленнее, но он по-прежнему достаточно быстрый. Во многих случаях простая линейная интерполяция (как я здесь использовал) будет полностью адекватной и чрезвычайно быстрой.

Кривая может быть полностью общей, даже пересекая ее. Я приведу простой пример для пространственной кривой на 3-й:

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) 

enter image description here

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

enter image description here

+0

wow это выглядит действительно многообещающим, кривая не нужно закрывать? – user1938107

+0

Кривая может быть полностью общей, без необходимости ее закрывать. Однако я предоставил эту возможность, если первая и последняя точки совпадают. –

+1

У вас есть алгоритм, записанный? Я не использую Matlab, и довольно сложно разобрать то, что происходит – user1938107

0

Не уверен, что я следую, но вместо хранения фактических данных, возможно, храните дельту от точки к точке, а затем перестройте кривую из дельт, так что не было бы никаких пятен? Это, однако, изменило бы форму кривой.

2

Ваша «кривая» - это куча сегментов, которые соединяют кучу точек. Каждый сегмент линии имеет длину; общая длина вашей кривой - это сумма этих длин линий.

Итак, вычислите d = totalCurveLength/(numberOfPoints - 1) и разделите кривую на (numberOfPoints - 1) куски длины d.

2

Прежде всего, спасибо г-ну Джону D'Errico для interparc , Какая отличная работа!

Я тоже столкнулся с этой проблемой, но не знаком с API-интерфейсом MATLAB. Учитывая это, я попытался преобразовать часть кода Interparc Matlab в Python (просто включив линейную интерполяцию, потому что этого было бы достаточно для решения моей проблемы).

И вот мой код; надеюсь, что он может помочь всем питоникам искать что-то подобное:

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 
+0

Я скоро загружу, но я работал над этим с некоторыми учениками и придумал полный код. но да, это полезно многим людям, я думаю, – user1938107

+0

Мне пришлось изменить ваш «|» оператор в двух строках «tbins [np.where ...]» до np.bitwise_or; иначе они не будут работать так, как вы планировали (я думаю). Я также прокомментировал блок закрытия кривой, поскольку он создавал нечетное поведение для моего приложения без закрытой кривой. В противном случае, хорошая работа. Я надеюсь, что кто-то pythonizes полный interparc-код, поскольку он невероятно полезен. – Jon

Смежные вопросы