我正在尝试编写一种方法,使用开始时的加速和结束时的减速(缓出/缓和),随着时间的推移,从0到x(一维中对象的位置)进行插值。 提供的总时间,以及加速和减速的持续时间。动作应该复制惯性效应,我正在考虑Hermite curve非线性部分。
double Interpolate(
double timeToAccel, double timeCruising, double timeToDecel,
double finalPosition,
double currentTime)
{
//...
}
有人可以指出我做的那部分代码吗?我不知道如何整合Hermite曲线,因此不知道我将在加速部分或减速部分移动多少,反过来我无法弄清楚线性速度是多少部分。
感谢。
Some reference来说明我的问题。
修改:
编辑:Roman和Bob10提供了完整的解决方案。我实现了罗马的代码。谢谢你们两个,伙计们!我感谢您的完美支持和详细的解决方案,为您节省了长时间的搜索和试用。
答案 0 :(得分:22)
首先,让我们制作一个三次Hermite样条函数:
/*
t - in interval <0..1>
p0 - Start position
p1 - End position
m0 - Start tangent
m1 - End tangent
*/
double CubicHermite(double t, double p0, double p1, double m0, double m1) {
t2 = t*t;
t3 = t2*t;
return (2*t3 - 3*t2 + 1)*p0 + (t3-2*t2+t)*m0 + (-2*t3+3*t2)*p1 + (t3-t2)*m1;
}
现在你的任务是为缓入和缓出部分计算p0,p1,m0和m1。让我们添加一些变量来使数学运算更容易:
double Interpolate(
double timeToAccel, double timeCruising, double timeToDecel,
double finalPosition,
double currentTime) {
double t1 = timeToAccel;
double t2 = timeCruising;
double t3 = timeToDecel;
double x = finalPosition;
double t = currentTime;
我们需要指定当物体停止加速并开始减速时应该在哪里。您可以随意指定这些,但仍能产生平滑的运动,但是,我们想要一个有点“自然”的解决方案。
假设巡航速度为v
。在crusing期间,对象移动距离x2 = v * t2
。现在,当物体从0加速到速度v时,它会移动距离x1 = v * t1 / 2
。同样适用于减速x3 = v * t3 / 2
。全部放在一起:
x1 + x2 + x3 = x
v * t1 / 2 + v * t2 + v * t3 / 2 = x
由此我们可以计算出我们的速度和距离:
double v = x / (t1/2 + t2 + t3/2);
double x1 = v * t1 / 2;
double x2 = v * t2;
double x3 = v * t3 / 2;
现在我们知道了一切,我们只是将它输入我们的立方Hermite样条插值器
if(t <= t1) {
// Acceleration
return CubicHermite(t/t1, 0, x1, 0, v*t1);
} else if(t <= t1+t2) {
// Cruising
return x1 + x2 * (t-t1) / t2;
} else {
// Deceleration
return CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0);
}
}
我在Excel中测试了这个,这是与之相同的VBA代码。对于边界条件,有一些除以零的分歧,我把这个作为练习器给读者留下了
Public Function CubicHermite(t As Double, p0 As Double, p1 As Double, _
m0 As Double, m1 As Double) As Double
t2 = t * t
t3 = t2 * t
CubicHermite = (2 * t3 - 3 * t2 + 1) * p0 + _
(t3 - 2 * t2 + t) * m0 + (-2 * t3 + 3 * t2) * p1 + (t3 - t2) * m1
End Function
Public Function Interpolate(t1 As Double, t2 As Double, t3 As Double, _
x As Double, t As Double) As Double
Dim x1 As Double, x2 As Double, x3 As Double
v = x / (t1 / 2 + t2 + t3 / 2)
x1 = v * t1 / 2
x2 = v * t2
x3 = v * t3 / 2
If (t <= t1) Then
Interpolate = CubicHermite(t / t1, 0, x1, 0, v*t1)
ElseIf t <= t1 + t2 Then
Interpolate = x1 + x2 * (t - t1) / t2
Else
Interpolate = CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0)
End If
End Function
答案 1 :(得分:8)
使用常规恒定加速可以直接进行。那么问题就变成你需要加速到什么速度(v)以便在适当的时间内完成旅程,这将告诉你达到该速度所需的加速度。
如果总时间是t_t且加速时间是t_a,那么你有两个加速和减速部分以及恒速部分行进的距离:
x = 2*(a*t_a*t_a/2) + v*(t_t-2*t_a)
这可以通过在v = a * t_a中进行加速来求解
来解决a = x/(t_a*(t_t - t_a))
这是一些使用和绘制这些方程式结果的Python代码,它显示了如何使用方程式以及结果如何:
from pylab import *
t_a, t_t, D = 3., 10., 1. # input values
a = D/(t_a*(t_t - t_a))
segments = (t_a, a), (t_t-2*t_a, 0.), (t_a, -a) # durations and accelerations for each segment
t0, x0, v0 = 0.0, 0.0, 0.0 #initial values for the segment
tdata, xdata = [], []
for t_segment, a in segments: # loop over the three segments
times = arange(0, t_segment, .01)
x = x0 + v0*times + .5*a*times*times
xdata.append(x)
tdata.append(times+t0)
x0 = x[-1] # the last x calculated in the segment above
v0 += a*t_segment
t0 += t_segment
plot(tdata[0], xdata[0], 'r', tdata[1], xdata[1], 'r', tdata[2], xdata[2], 'r')
xlabel("time")
ylabel("position")
show()