Python中的参数曲面创建

3

有没有一个Python模块可以处理参数(u-v)曲面?我正在寻找的是类似于scipy.interpolate的样条函数的三维模拟,我可以通过一组2D点创建参数化样条曲线,如下所示:

xypts = [[0., 1., 5., 2.], [4., 3., 6., 7.]]
tck, u = scipy.interpolate.splprep(xypts, s=0, k=3)

然后可以像这样在样条曲线上的任意t值处获取一个点:

t = 0.5
intxypt = scipy.interpolate.splev(t, tck)

所以,我想要的是这样的东西:

如何实现:

# xyzpts is a 3 x m x n matrix, with m and n >= 4 for a cubic surface
tck, s, t = srfprep(xyzpts, s=0, k=3)
u, v = 0.5, 0.5
intxyzpt = srfev(u, v, tck)

我之前写了自己的代码来完成这个功能,但它速度很慢且不够稳定,特别是在表面边缘处。因此我正在寻找更标准和优化的解决方案。

1个回答

1

这可能很明显,但如果您能够猜测与每个数据点对应的坐标(最简单的情况是u=xv=y,如果曲面是一个图形),参数插值(u,v) -> (x,y,z)本质上是三个单独数据集(x、y和z坐标)的2-D插值,因此您可以使用任何通常的2-D插值方法。

实际上,splprep就是这样工作的,它假设点是有序的,并根据欧几里得距离分配坐标,即u[i] = u[i-1] + dist(p[i], p[j])。如果您知道哪些点“相邻”,则可以将其推广到2-D。例如,如果x,y,z数据以2-D数组的形式出现,则可以执行以下操作:

from scipy import interpolate
import numpy as np

# example dataset (wavy cylinder)

def surf(u, v):
    x = np.cos(v*np.pi*2) * (1 + 0.3*np.cos(30*u))
    y = np.sin(v*np.pi*2) * (1 + 0.3*np.cos(30*u))
    z = 2*u
    return x, y, z

ux, vx = np.meshgrid(np.linspace(0, 1, 20),
                     np.linspace(0, 1, 20))
x, y, z = surf(ux, vx)

# reconstruct (u, v) using the existing (!) neighbourhood information
du = np.sqrt(np.diff(x, axis=0)**2 + np.diff(y, axis=0)**2 + np.diff(z, axis=0)**2)
dv = np.sqrt(np.diff(x, axis=1)**2 + np.diff(y, axis=1)**2 + np.diff(z, axis=1)**2)
u = np.zeros_like(x)
v = np.zeros_like(x)
u[1:,:] = np.cumsum(du, axis=0)
v[:,1:] = np.cumsum(dv, axis=1)

u /= u.max(axis=0)[None,:] # hmm..., or maybe skip this scaling step -- may distort the result
v /= v.max(axis=1)[:,None]

# construct interpolant (unstructured grid)
ip_surf = interpolate.CloughTocher2DInterpolator(
        (u.ravel(), v.ravel()), 
        np.c_[x.ravel(), y.ravel(), z.ravel()])

# the BivariateSpline classes might also work here, but the above is more robust

# plot projections
import matplotlib.pyplot as plt

u = np.random.rand(2000)
v = np.random.rand(2000)

plt.subplot(131)
plt.plot(ip_surf(u, v)[:,0], ip_surf(u, v)[:,1], '.')
plt.title('xy')
plt.subplot(132)
plt.plot(ip_surf(u, v)[:,1], ip_surf(u, v)[:,2], '.')
plt.title('yz')
plt.subplot(133)
plt.plot(ip_surf(u, v)[:,2], ip_surf(u, v)[:,0], '.')
plt.title('zx')
plt.show()

编辑: 嗯,我不确定上面计算出的u,v在实践中有多么健壮,因为似乎存在畸变的可能。然而,在这方面下面的局部线性嵌入可能更有效。

如果您不能猜测u,v值,例如您只有一堆点而没有邻域信息,则问题变得更加困难。适当的关键词似乎是“表面重建”和“流形学习”。

我没有尝试过,但我认为您可以轻松使用scikits-learn中的LocallyLinearEmbedding获取合适的u,v坐标,请参见此示例。他们有许多不同的算法,这似乎足够稳定。然后,您可以将结果u=Y [:,0];v=Y [:,1]用于非结构化的二维插值方法,如上所示。

也许通过更多的谷歌搜索可以发现更多的包。


不,那并不明显(头抱怨)!你给了我创造更好实现方案所需的洞察力,谢谢。就记录而言,这些是我正在创建的翼型曲面,由具有相同点数的截面曲线组成。我已经从这些曲线中获取到'u'值;'v'值仅仅是相对截面高度。 - subnivean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接