2018-03-30 18:19:23 -07:00
|
|
|
import numpy as np
|
2018-03-31 15:11:35 -07:00
|
|
|
|
2018-12-24 12:37:51 -08:00
|
|
|
from manimlib.utils.bezier import bezier
|
|
|
|
from manimlib.utils.simple_functions import sigmoid
|
2018-03-30 18:19:23 -07:00
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
|
2018-05-08 16:19:42 +02:00
|
|
|
def linear(t):
|
|
|
|
return t
|
|
|
|
|
2018-05-30 12:02:35 -07:00
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
def smooth(t, inflection=10.0):
|
2018-03-30 18:19:23 -07:00
|
|
|
error = sigmoid(-inflection / 2)
|
2018-04-06 13:58:59 -07:00
|
|
|
return (sigmoid(inflection * (t - 0.5)) - error) / (1 - 2 * error)
|
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
|
|
|
|
def rush_into(t):
|
2018-04-06 13:58:59 -07:00
|
|
|
return 2 * smooth(t / 2.0)
|
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
|
|
|
|
def rush_from(t):
|
2018-04-06 13:58:59 -07:00
|
|
|
return 2 * smooth(t / 2.0 + 0.5) - 1
|
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
|
|
|
|
def slow_into(t):
|
2018-04-06 13:58:59 -07:00
|
|
|
return np.sqrt(1 - (1 - t) * (1 - t))
|
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
|
|
|
|
def double_smooth(t):
|
|
|
|
if t < 0.5:
|
2018-04-06 13:58:59 -07:00
|
|
|
return 0.5 * smooth(2 * t)
|
2018-03-30 18:19:23 -07:00
|
|
|
else:
|
2018-04-06 13:58:59 -07:00
|
|
|
return 0.5 * (1 + smooth(2 * t - 1))
|
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
def there_and_back(t, inflection=10.0):
|
|
|
|
new_t = 2 * t if t < 0.5 else 2 * (1 - t)
|
2018-03-30 18:19:23 -07:00
|
|
|
return smooth(new_t, inflection)
|
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
|
2018-05-02 08:17:34 -07:00
|
|
|
def there_and_back_with_pause(t, pause_ratio=1. / 3):
|
|
|
|
a = 1. / pause_ratio
|
|
|
|
if t < 0.5 - pause_ratio / 2:
|
|
|
|
return smooth(a * t)
|
|
|
|
elif t < 0.5 + pause_ratio / 2:
|
2018-03-30 18:19:23 -07:00
|
|
|
return 1
|
|
|
|
else:
|
2018-05-02 08:17:34 -07:00
|
|
|
return smooth(a - a * t)
|
2018-04-06 13:58:59 -07:00
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
def running_start(t, pull_factor=-0.5):
|
2018-03-30 18:19:23 -07:00
|
|
|
return bezier([0, 0, pull_factor, pull_factor, 1, 1, 1])(t)
|
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
|
|
|
|
def not_quite_there(func=smooth, proportion=0.7):
|
2018-03-30 18:19:23 -07:00
|
|
|
def result(t):
|
2018-04-06 13:58:59 -07:00
|
|
|
return proportion * func(t)
|
2018-03-30 18:19:23 -07:00
|
|
|
return result
|
|
|
|
|
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
def wiggle(t, wiggles=2):
|
|
|
|
return there_and_back(t) * np.sin(wiggles * np.pi * t)
|
|
|
|
|
|
|
|
|
|
|
|
def squish_rate_func(func, a=0.4, b=0.6):
|
2018-03-30 18:19:23 -07:00
|
|
|
def result(t):
|
|
|
|
if a == b:
|
|
|
|
return a
|
|
|
|
|
|
|
|
if t < a:
|
|
|
|
return func(0)
|
|
|
|
elif t > b:
|
|
|
|
return func(1)
|
|
|
|
else:
|
2018-04-06 13:58:59 -07:00
|
|
|
return func((t - a) / (b - a))
|
|
|
|
|
2018-03-30 18:19:23 -07:00
|
|
|
return result
|
|
|
|
|
|
|
|
# Stylistically, should this take parameters (with default values)?
|
|
|
|
# Ultimately, the functionality is entirely subsumed by squish_rate_func,
|
2018-04-06 13:58:59 -07:00
|
|
|
# but it may be useful to have a nice name for with nice default params for
|
2018-03-30 18:19:23 -07:00
|
|
|
# "lingering", different from squish_rate_func's default params
|
|
|
|
|
|
|
|
|
2018-04-06 13:58:59 -07:00
|
|
|
def lingering(t):
|
|
|
|
return squish_rate_func(lambda t: t, 0, 0.8)(t)
|
2018-05-10 00:00:15 +02:00
|
|
|
|
|
|
|
|
2018-07-14 10:31:56 -07:00
|
|
|
def exponential_decay(t, half_life=0.1):
|
|
|
|
# The half-life should be rather small to minimize
|
|
|
|
# the cut-off error at the end
|
|
|
|
return 1 - np.exp(-t / half_life)
|