简体   繁体   English

数学:缓和,使用具有时间约束的Hermite曲线缓和位移

[英]Math: Ease In, ease Out a displacement using Hermite curve with time constraint

I'm trying to write a method that interpolates from 0 to x (position of an object in one dimension) over time using acceleration at the beginning and deceleration at the end (ease out / ease in) with the only constraints that the total time is provided , as well as the duration of the acceleration and deceleration . 我正在尝试使用开始时的加速和结束时的减速(缓出/缓和)来编写一个从0到x(一维中物体的位置)的插值方法,其中只有总时间的限制提供 了加速和减速持续时间 the motion should replicate the inertia effect and I'm considering a Hermite curve for the non-linear portions. 运动应该复制惯性效应,我正在考虑非线性部分的Hermite曲线

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime)
{
    //...
}

Can someone point me out to a portion of code that does that? 有人能指出我做的那部分代码吗? I don't know how to integrate the Hermite curve, hence don't know how much I'll move in the accelerating portion or in the decelerating portion, and in turn I can't figure out what will be the speed in the linear portion. 我不知道如何整合Hermite曲线,因此不知道我将在加速部分或减速部分移动多少,反过来我无法弄清楚线性速度是多少一部分。

Thanks. 谢谢。

Some reference to illustrate my question. 一些参考来说明我的问题。

Edit : 编辑

  • start and end speeds are null, and the current time is also part of the parameters in the method, I've updated the signature. 开始和结束速度为空,当前时间也是方法中参数的一部分,我已更新签名。
  • basically the idea is to imagine a move at constant speed on a distance d, this gives a total duration. 基本上这个想法是想象在距离d上以恒定速度移动,这给出了总持续时间。 Then we add the acceleration and deceleration phases, while maintaining the same duration, hence we have an unknown new cruise speed to determinate (because we move less in the Hermite phases than in the linear phases they have replaced). 然后我们添加加速和减速阶段,同时保持相同的持续时间,因此我们有一个未知的新巡航速度来确定(因为我们在Hermite阶段的移动少于他们已经替换的线性阶段)。 Maybe the amount of move lost in the Hermite phases, compared to a linear move of the same duration is the ratio between the top and bottom area in the curves, just an idea from a non expert. 与相同持续时间的线性移动相比,Hermite阶段中的移动量可能是曲线中顶部和底部区域之间的比率,这只是来自非专家的想法。

Edit : Roman and Bob10 have provided full working solutions. 编辑 :Roman和Bob10提供了完整的工作解决方案。 I implemented the code from Roman. 我实现了罗马的代码。 Thanks to you both, guys! 谢谢你们两个,伙计们! I appreciate your perfect support and your detailed solutions, you saved me long searches and trials. 我感谢您的完美支持和详细的解决方案,为您节省了长时间的搜索和试用。

First, let's make a cubic hermite spline function: 首先,让我们制作一个三次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;
}

Now your task is to calculate the p0, p1, m0 and m1 for both ease-in and ease-out portions. 现在你的任务是计算缓入和缓出部分的p0,p1,m0和m1。 Let us add a few variables to make the math a bit easier to write: 让我们添加一些变量来使数学运算更容易:

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;

We need to specify where should the object be when it stops accelerating and starts decelerating. 我们需要指定当物体停止加速并开始减速时应该在哪里。 You can specify these however you please and still produce a smooth movement, however, we would like a somewhat "natural" solution. 您可以随意指定这些,但仍能产生平滑的运动,但是,我们想要一个有点“自然”的解决方案。

Let's assume that the cruising speed is v . 我们假设巡航速度是v During crusing, the object travels distance x2 = v * t2 . 在crusing期间,物体行进距离x2 = v * t2 Now, when the object accelerates from 0 to speed v, it travels distance x1 = v * t1 / 2 . 现在,当物体从0加速到速度v时,它行进距离x1 = v * t1 / 2 Same for deceleration x3 = v * t3 / 2 . 减速度相同x3 = v * t3 / 2 Put all together: 全部放在一起:

x1 + x2 + x3 = x x1 + x2 + x3 = x

v * t1 / 2 + v * t2 + v * t3 / 2 = x v * t1 / 2 + v * t2 + v * t3 / 2 = x

From that we can calculate our speed and the distances: 由此我们可以计算出我们的速度和距离:

    double v = x / (t1/2 + t2 + t3/2);
    double x1 = v * t1 / 2;
    double x2 = v * t2;
    double x3 = v * t3 / 2;

And now that we know everything, we just feed it into our cubic hermite spline interpolator 现在我们知道了一切,我们只需将其输入到我们的立方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);
    }
}

I tested this in Excel, here's the equivalent VBA code to play with. 我在Excel中测试了这个,这是与之相当的等效VBA代码。 There are some divisions by zero for boundary conditions, I leave fix to this as an excercise to the reader 对于边界条件,有一些除以零的分歧,我将此作为练习给读者留下了解决方法


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

This is straightforward using normal constant acceleration. 使用常规恒定加速可以很简单。 Then the question becomes what velocity (v) do you need to accelerate to in order to complete the trip in the right amount of time, and this will tell you the acceleration you need to get to that velocity. 那么问题就变成你需要加速到什么速度(v)以便在适当的时间内完成旅程,这将告诉你达到该速度所需的加速度。

If the total time is t_t and the time of acceleration is t_a, then you have the distance traveled as the two accelerating and decelerating parts, and the constant velocity part: 如果总时间是t_t且加速时间是t_a,那么你有两个加速和减速部分以及恒速部分的行进距离:

x = 2*(a*t_a*t_a/2) + v*(t_t-2*t_a)

This can be solved for the acceleration by subbing in v=a*t_a, to find 这可以通过在v = a * t_a中进行加法来求解加速度来求解

a = x/(t_a*(t_t - t_a))

Here's some Python code that uses and plots the result of these equations, that shows both how to use the equations and what the result looks like: 下面是一些使用和绘制这些方程式结果的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()

替代文字

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM