扩展ev-br 的答案,这里有一些示例代码,举例说明了在具有规定导数的n维BPoly.from_derivatives
点之间进行插值的用法。
import numpy as np
from scipy import interpolate
def sampleCubicSplinesWithDerivative(points, tangents, resolution):
'''
Compute and sample the cubic splines for a set of input points with
optional information about the tangent (direction AND magnitude). The
splines are parametrized along the traverse line (piecewise linear), with
the resolution being the step size of the parametrization parameter.
The resulting samples have NOT an equidistant spacing.
Arguments: points: a list of n-dimensional points
tangents: a list of tangents
resolution: parametrization step size
Returns: samples
Notes: Lists points and tangents must have equal length. In case a tangent
is not specified for a point, just pass None. For example:
points = [[0,0], [1,1], [2,0]]
tangents = [[1,1], None, [1,-1]]
'''
resolution = float(resolution)
points = np.asarray(points)
nPoints, dim = points.shape
# Parametrization parameter s.
dp = np.diff(points, axis=0) # difference between points
dp = np.linalg.norm(dp, axis=1) # distance between points
d = np.cumsum(dp) # cumsum along the segments
d = np.hstack([[0],d]) # add distance from first point
l = d[-1] # length of point sequence
nSamples = int(l/resolution) # number of samples
s,r = np.linspace(0,l,nSamples,retstep=True) # sample parameter and step
# Bring points and (optional) tangent information into correct format.
assert(len(points) == len(tangents))
data = np.empty([nPoints, dim], dtype=object)
for i,p in enumerate(points):
t = tangents[i]
# Either tangent is None or has the same
# number of dimensions as the point p.
assert(t is None or len(t)==dim)
fuse = list(zip(p,t) if t is not None else zip(p,))
data[i,:] = fuse
# Compute splines per dimension separately.
samples = np.zeros([nSamples, dim])
for i in range(dim):
poly = interpolate.BPoly.from_derivatives(d, data[:,i])
samples[:,i] = poly(s)
return samples
为了演示这个函数的使用,我们指定了点和切线。该示例进一步演示了如果切线的“大小”发生更改时的效果。
# Input.
points = []
tangents = []
resolution = 0.2
points.append([0.,0.]); tangents.append([1,1])
points.append([3.,4.]); tangents.append([1,0])
points.append([5.,2.]); tangents.append([0,-1])
points.append([3.,0.]); tangents.append([-1,-1])
points = np.asarray(points)
tangents = np.asarray(tangents)
# Interpolate with different tangent lengths, but equal direction.
scale = 1.
tangents1 = np.dot(tangents, scale*np.eye(2))
samples1 = sampleCubicSplinesWithDerivative(points, tangents1, resolution)
scale = 2.
tangents2 = np.dot(tangents, scale*np.eye(2))
samples2 = sampleCubicSplinesWithDerivative(points, tangents2, resolution)
scale = 0.1
tangents3 = np.dot(tangents, scale*np.eye(2))
samples3 = sampleCubicSplinesWithDerivative(points, tangents3, resolution)
# Plot.
import matplotlib.pyplot as plt
plt.scatter(samples1[:,0], samples1[:,1], marker='o', label='samples1')
plt.scatter(samples2[:,0], samples2[:,1], marker='o', label='samples2')
plt.scatter(samples3[:,0], samples3[:,1], marker='o', label='samples3')
plt.scatter(points[:,0], points[:,1], s=100, c='k', label='input')
plt.axis('equal')
plt.title('Interpolation')
plt.legend()
plt.show()
这导致以下情节:
需要注意的三点:
- 以下也可以应用于两个以上的维度。
- 样本之间的间距不固定。实现等距采样的一种简单方法是在返回的数据之间进行线性插值
samples
,正如本文中所讨论的那样。
- 切线的指定是可选的,但
BPoly.from_derivatives
不能确保该位置的样条线之间的平滑过渡。例如,如果tangents[1]
在上面的示例中设置为None
, sampleCubicSplinesWithDerivative(points, tangents, resolution)
,结果将如下所示: