Математика: Осторожно введите, ослабьте смещение с помощью кривой Hermite с ограничением времени

Я пытаюсь записать метод, который интерполирует от 0 до x (положение объекта в одном размере) со временем использование ускорения вначале, и замедление в конце (ослабьте / осторожно вводят) с единственными ограничениями, которые общее время обеспечивается, а также продолжительность ускорения и замедления. движение должно копировать эффект инерции, и я рассматриваю кривую Hermite для нелинейных частей.

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

Кто-то может указать на меня части кода, который делает это? Я не знаю, как интегрировать кривую Hermite, следовательно не знайте, сколько я перемещу в ускоряющуюся часть или в замедляющуюся часть, и в свою очередь я не могу выяснить то, что будет скоростью в линейной части.

Спасибо.

Некоторая ссылка для иллюстрирования моего вопроса.

Править:

  • запустите и закончитесь, скорости являются пустыми, и текущее время является также частью параметров в методе, я обновил подпись.
  • в основном идея состоит в том, чтобы вообразить перемещение в постоянной скорости на расстоянии d, это дает общую продолжительность. Затем мы добавляем ускорение и фазы замедления при поддержании той же продолжительности, следовательно у нас есть неизвестная новая скорость круиза к определенному (потому что мы перемещаемся меньше в фазы Hermite, чем в линейных фазах, которые они заменили). Возможно, объем перемещения, потерянного в фазах Hermite, по сравнению с линейным перемещением той же продолжительности, является отношением между вершиной и нижней областью в кривых, просто идея от не опытный.

Править: Римлянин и Bob10 предоставили полные рабочие решения. Я реализовал код от римлянина. Благодаря Вам обоим, парням! Я ценю Вашу идеальную поддержку и Ваши подробные решения, Вы сохранили меня, долго ищет и испытывает.

12
задан 742 1 August 2010 в 17:10
поделиться

2 ответа

Сначала создадим кубическую сплайн-функцию Эрмита:

/*
  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 для порций easy-in и ease-out. Давайте добавим несколько переменных, чтобы облегчить математику:

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. Во время движения объект проходит расстояние 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;

И теперь, когда мы знаем все, мы просто вводим это в наш кубический интерполятор эрмитового сплайна

    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
22
ответ дан 2 December 2019 в 05:03
поделиться

Это просто, используя обычное постоянное ускорение. Тогда возникает вопрос, до какой скорости (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()

alt text

8
ответ дан 2 December 2019 в 05:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: