我有 2 个二维坐标。比如说,(x_1, y_1)
是时间t = 1
的点,(x_2, y_2)
是时间t = 10
的点。我想在1
到10
时间步之间线性插值,即2,3,...9
.
如何在python中做到这一点?
您可以使用这两个点计算直线的方程,然后使用该方程生成尽可能多的点。但是与时间的关系取决于您想要的运动类型(缓出、缓和、线性)
(Y - y2)/(X - x2) = (y2 - y1)(x2 - x1)
这是等式。您可以使用实际值并得到 X 和 Y 的方程。 然后将 Y 值计算为给定的 X 值。
这应该有效。您可以给seek
一个介于 0 和 1 之间的值以获得中间坐标
def interpolate(x1, y1, x2, y2, seek):
X = x1 + x2*seek
Y = y2 + (y2 - y1)(X - x2)/(x2 - x1)
return (X,Y)
你想要做的称为线性插值,这可以通过lerp()
函数来完成:
from __future__ import division # For Python 2
def lerp(t, times, points):
dx = points[1][0] - points[0][0]
dy = points[1][1] - points[0][1]
dt = (t-times[0]) / (times[1]-times[0])
return dt*dx + points[0][0], dt*dy + points[0][1]
x_1, y_1 = 1, 2
x_2, y_2 = -3, 4
times = [1, 10]
points = [(x_1, y_1), (x_2, y_2)]
for v in range(1, 11):
print('{:2d} -> ({:6.3f}, {:6.3f})'.format(v, *lerp(v, times, points)))
输出:
1 -> ( 1.000, 2.000)
2 -> ( 0.556, 2.222)
3 -> ( 0.111, 2.444)
4 -> (-0.333, 2.667)
5 -> (-0.778, 2.889)
6 -> (-1.222, 3.111)
7 -> (-1.667, 3.333)
8 -> (-2.111, 3.556)
9 -> (-2.556, 3.778)
10 -> (-3.000, 4.000)
一种更有效的方法,每次迭代的计算次数要少得多,可以通过将lerp()
转换为生成器函数来实现。由于连续添加中的累积误差,此方法的准确性略低。
from __future__ import division # For Python 2
def lerp(times, points, steps):
divisor = steps-1
dt = (times[1] - times[0]) / divisor
dx = (points[1][0] - points[0][0]) / divisor
dy = (points[1][1] - points[0][1]) / divisor
t, x, y = (times[0],) + points[0]
for _ in range(steps):
yield t, x, y
t += dt
x += dx
y += dy
x_1, y_1 = 1, 2
x_2, y_2 = -3, 4
times = [1, 10]
points = [(x_1, y_1), (x_2, y_2)]
steps= times[1] - times[0] + 1
for t, x, y in lerp(times, points, steps):
print('{:6.2f} -> ({:6.3f}, {:6.3f})'.format(t, x, y))
面向对象的方法
如果要经常调用它,则可能需要麻烦对其进行优化,这样它就不需要在每次调用时都相同的调用之间重新计算这么多值。一种方法是使用__call__()
方法使其成为class
。这样,所有初步计算都可以在首次构造时完成,然后在以后使用不同的时间参数调用对象时重用。如果需要,它还使每个对象同时拥有和使用多个Lerp
对象或它们的容器。
像这样的类有时被称为"函子",因为它们是函数和对象的组合(尽管普通函数已经是 Python 中的对象,但它们并不那么灵活且易于定制)。
我的意思是:
from __future__ import division # For Python 2
class Lerp(object):
def __init__(self, times, points):
self.t0 = times[0]
self.p0 = points[0]
self.dt = times[1] - times[0]
self.dx = points[1][0] - points[0][0]
self.dy = points[1][1] - points[0][1]
def __call__(self, t):
dt = (t-self.t0) / self.dt
return dt*self.dx + self.p0[0], dt*self.dy + self.p0[1]
x_1, y_1 = 1, 2
x_2, y_2 = -3, 4
times = [1, 10]
points = [(x_1, y_1), (x_2, y_2)]
lerp = Lerp(times, points)
for v in range(1, 11):
print('{:2d} -> ({:6.3f}, {:6.3f})'.format(v, *lerp(v)))