"""
Basic Usage: Eases
==================
The easing operation functions (eases) are used to change the values
within a set of image data. Using an easing operation (an "ease")
works like any other function.
Usage::
>>> import numpy as np
>>> a = np.array([[[0., .25, .5, .75, 1.], [0., .25, .5, .75, 1.]]])
>>> in_circ(a)
array([[[0. , 0.03175416, 0.1339746 , 0.33856217, 1. ],
[0. , 0.03175416, 0.1339746 , 0.33856217, 1. ]]])
The functions themselves are simple. They all adhere to the Easing Operation
protocol:
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
Value Scaling
=============
Eases work best on image data. That is to say, they work best on arrays of
floating point data with values from zero to one. This is because the
math in many of the eases relies on the fact that multiplication results
in a smaller number and division results in a larger one.
What happens if you pass an array with numbers outside of that range?
If you pass an array with values less than zero or greater than one, the
:func:'pjimg.eases.will_scale' decorator will scale the data before
passing it to the ease and then unscale result before returning it.
What happens when the data is scaled?
When scaling the data, the function:
* Sets the lowest value to zero,
* Sets the highest value to one,
* Sets the rest of the values to their proportional location between
the lowest and the highest value.
It will then undo that scaling before returning the eased data.
This can result in some undesirable results if the lowest or highest value
in the data isn't the lowest or highest value in the value range you are
working in. For example, if you are working with the range 0–255 but the
lowest and highest values in the data are 127 and 215, the ease will
act like you are working in the range 127–215.
If this will cause problems for your code, you should scale the data
yourself before using the easing function.
Easing Operations
=================
The following are the easing functions available in :mod:`pjimg`.
Ease In
-------
These functions start slow or extend the darkness in an image:
.. autofunction:: pjimg.eases.in_back
.. autofunction:: pjimg.eases.in_bounce
.. autofunction:: pjimg.eases.in_circ
.. autofunction:: pjimg.eases.in_cubic
.. autofunction:: pjimg.eases.in_elastic
.. autofunction:: pjimg.eases.in_expo
.. autofunction:: pjimg.eases.in_quad
.. autofunction:: pjimg.eases.in_quart
.. autofunction:: pjimg.eases.in_quint
.. autofunction:: pjimg.eases.in_sin
Ease Out
--------
These functions start fast or extend the lightness in an image:
.. autofunction:: pjimg.eases.out_back
.. autofunction:: pjimg.eases.out_bounce
.. autofunction:: pjimg.eases.out_circ
.. autofunction:: pjimg.eases.out_cubic
.. autofunction:: pjimg.eases.out_elastic
.. autofunction:: pjimg.eases.out_expo
.. autofunction:: pjimg.eases.out_quad
.. autofunction:: pjimg.eases.out_quart
.. autofunction:: pjimg.eases.out_quint
.. autofunction:: pjimg.eases.out_sin
Ease In Out
-----------
These functions go fast in the middle or compress the midtones of the image.
.. autofunction:: pjimg.eases.in_out_back
.. autofunction:: pjimg.eases.in_out_bounce
.. autofunction:: pjimg.eases.in_out_circ
.. autofunction:: pjimg.eases.in_out_cos
.. autofunction:: pjimg.eases.in_out_cubic
.. autofunction:: pjimg.eases.in_out_elastic
.. autofunction:: pjimg.eases.in_out_expo
.. autofunction:: pjimg.eases.in_out_perlin
.. autofunction:: pjimg.eases.in_out_quad
.. autofunction:: pjimg.eases.in_out_quart
.. autofunction:: pjimg.eases.in_out_quint
.. autofunction:: pjimg.eases.in_out_sin
Ease Mid
--------
These functions change the values in the data, making the midtones dark
and the edges light.
.. autofunction:: pjimg.eases.mid_bump_linear
.. autofunction:: pjimg.eases.mid_bump_sin
Registration
============
All easing functions are registered in :class:`dict`
`pjimg.eases.eases` for convenience, but they can also
be called directly.
"""
import numpy as np
from pjimg.eases.decorators import register, will_scale
from pjimg.eases.model import Ease, eases
from pjimg.util import ImgAry
# Names available for import.
__all__ = [
'in_back',
'in_bounce',
'in_circ',
'in_cubic',
'in_elastic',
'in_expo',
'in_out_back',
'in_out_bounce',
'in_out_circ',
'in_out_cos',
'in_out_cubic',
'in_out_elastic',
'in_out_expo',
'in_out_perlin',
'in_out_quad',
'in_out_quart',
'in_out_quint',
'in_out_sin',
'in_quad',
'in_quart',
'in_quint',
'in_sin',
'mid_bump_linear',
'mid_bump_sin',
'out_back',
'out_bounce',
'out_circ',
'out_cubic',
'out_elastic',
'out_expo',
'out_quad',
'out_quart',
'out_quint',
'out_sin',
]
# Ease in functions.
[docs]
@register(eases)
@will_scale
def in_back(a: ImgAry) -> ImgAry:
"""An easing function that backs up a little before starting.
.. figure:: images/plot_in_back.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_back`.
With image data, it extends the darker areas and compresses the
lighter ones. The dip into negative values can be a little
awkward. It's left to the calling application to decide how to
handle it. In the following example, values are just truncated at
zero.
.. figure:: images/ex_in_back.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_back` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
c1 = 1.70158
c3 = c1 + 1
return c3 * a ** 3 - c1 * a ** 2
[docs]
@register(eases)
@will_scale
def in_bounce(a: ImgAry) -> ImgAry:
"""An easing function that has a bounce.
.. figure:: images/plot_in_bounce.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_bounce`.
With image data, it is a large extension of the lighter areas
with multiple peaks and compression of the darker ones.
.. figure:: images/ex_in_bounce.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_bounce` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - out_bounce(1 - a)
[docs]
@register(eases)
@will_scale
def in_circ(a: ImgAry) -> ImgAry:
"""An easing function that has a circular curve.
.. figure:: images/plot_in_circ.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_circ`.
With image data, it is a moderate extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_circ.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_circ` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - np.sqrt(1 - a ** 2)
[docs]
@register(eases)
@will_scale
def in_cubic(a: ImgAry) -> ImgAry:
"""An easing function that has a cubic curve.
.. figure:: images/plot_in_cubic.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_cubic`.
With image data, it is a moderate extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_cubic.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_cubic` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return a ** 3
[docs]
@register(eases)
@will_scale
def in_elastic(a: ImgAry) -> ImgAry:
"""An easing function that bounces.
.. figure:: images/plot_in_elastic.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_elastic`.
With image data, it extends the darker areas and compresses the
lighter ones. The dip into negative values can be a little
awkward. It's left to the calling application to decide how to
handle it. In the following example, values are just truncated at
zero.
.. figure:: images/ex_in_elastic.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_elastic` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
c4 = (2 * np.pi) / 3
m = np.zeros(a.shape, bool)
m[a == 0] = True
m[a == 1] = True
a[~m] = -(2 ** (10 * a[~m] - 10)) * np.sin((a[~m] * 10 - 10.75) * c4)
return a
[docs]
@register(eases)
@will_scale
def in_expo(a: ImgAry) -> ImgAry:
"""An easing function that has an exponential curve.
.. figure:: images/plot_in_expo.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_expo`.
With image data, it is a moderate extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_expo.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_expo` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[a != 0] = 2 ** (10 * a[a !=0] - 10)
return a
[docs]
@register(eases)
@will_scale
def in_quad(a: ImgAry) -> ImgAry:
"""An easing function that has a quadratic curve.
.. figure:: images/plot_in_quad.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_quad`.
With image data, it is a moderate extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_quad.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_quad` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return a ** 2
[docs]
@register(eases)
@will_scale
def in_quart(a: ImgAry) -> ImgAry:
"""An easing function that has a quadric curve.
.. figure:: images/plot_in_quart.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_quart`.
With image data, it is a moderate extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_quart.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_quart` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return a ** 4
[docs]
@register(eases)
@will_scale
def in_quint(a: ImgAry) -> ImgAry:
"""An easing function that has a quintic curve.
.. figure:: images/plot_in_quint.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_quint`.
With image data, it is a large extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_quint.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_quint` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return a ** 5
[docs]
@register(eases)
@will_scale
def in_sin(a: ImgAry) -> ImgAry:
"""An easing function that has a sine curve.
.. figure:: images/plot_in_sin.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_sin`.
With image data, it is a small extension of the darker areas
and compression of the lighter ones. This should not generate
values outside of the original range.
.. figure:: images/ex_in_sin.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_sin` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - np.cos(a * np.pi / 2)
# Ease out functions.
[docs]
@register(eases)
@will_scale
def out_back(a: ImgAry) -> ImgAry:
"""An easing function that backs up a little before ending.
.. figure:: images/plot_out_back.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_back`.
With image data, it extends the lighter areas and compresses the
darker ones. The dip into negative values can be a little
awkward. It's left to the calling application to decide how to
handle it. In the following example, values are just truncated at
zero.
.. figure:: images/ex_out_back.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_back` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
c1 = 1.70158
c3 = c1 + 1
return 1 + c3 * (a - 1) ** 3 + c1 * (a - 1) ** 2
[docs]
@register(eases)
@will_scale
def out_bounce(a: ImgAry) -> ImgAry:
"""An easing function that has a bounce.
.. figure:: images/plot_out_bounce.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_bounce`.
With image data, it is a large extension of the lighter areas
with multiple peaks and compression of the darker ones.
.. figure:: images/ex_out_bounce.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_bounce` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
n1 = 7.5625
d1 = 2.75
b = np.zeros(a.shape, dtype=a.dtype)
b[a >= 2.5 / d1] = n1 * (a[a >= 2.5 / d1] - 2.625 / d1) ** 2 + .984375
b[a < 2.5 / d1] = n1 * (a[a < 2.5 / d1] - 2.25 / d1) ** 2 + .9375
b[a < 2 / d1] = n1 * (a[a < 2 / d1] - 1.5 / d1) ** 2 + .75
b[a < 1 / d1] = n1 * a[a < 1 / d1] ** 2
return b
[docs]
@register(eases)
@will_scale
def out_circ(a: ImgAry) -> ImgAry:
"""An easing function that has a circular curve.
.. figure:: images/plot_out_circ.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_circ`.
With image data, it is a moderate extension of the lighter areas
and compression of the darker ones.
.. figure:: images/ex_out_circ.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_circ` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return np.sqrt(1 - (a - 1) ** 2)
[docs]
@register(eases)
@will_scale
def out_cubic(a: ImgAry) -> ImgAry:
"""An easing function that has a cubic curve.
.. figure:: images/plot_out_cubic.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_cubic`.
With image data, it is a moderate extension of the lighter areas
and compression of the darker ones.
.. figure:: images/ex_out_cubic.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_cubic` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - (1 - a) ** 3
[docs]
@register(eases)
@will_scale
def out_elastic(a: ImgAry) -> ImgAry:
"""An easing function that bounces.
.. figure:: images/plot_out_elastic.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_elastic`.
With image data, it extends the lighter areas and compresses the
darker ones. The bounce into values over one can be a little
awkward. It's left to the calling application to decide how to
handle it. In the following example, values are just truncated at
one.
.. figure:: images/ex_out_elastic.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_elastic` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
c4 = (2 * np.pi) / 3
m = np.zeros(a.shape, bool)
m[a == 0] = True
m[a == 1] = True
a[~m] = 2 ** (-10 * a[~m]) * np.sin((a[~m] * 10 - .75) * c4) + 1
return a
[docs]
@register(eases)
@will_scale
def out_expo(a: ImgAry) -> ImgAry:
"""An easing function that has an exponential curve.
.. figure:: images/plot_out_expo.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_expo`.
With image data, it extends the lighter areas and compresses the
darker ones. The bounce into values over one can be a little
awkward. It's left to the calling application to decide how to
handle it. In the following example, values are just truncated at
one.
.. figure:: images/ex_out_expo.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_expo` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[a != 1.0] = 1 - 2 ** (-10 * a[a != 1.0])
return a
[docs]
@register(eases)
@will_scale
def out_quad(a: ImgAry) -> ImgAry:
"""An easing function that has a quadratic curve.
.. figure:: images/plot_out_quad.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_quad`.
With image data, it is a moderate extension of the lighter areas
and compression of the darker ones.
.. figure:: images/ex_out_quad.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_quad` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - (1 - a) ** 2
[docs]
@register(eases)
@will_scale
def out_quart(a: ImgAry) -> ImgAry:
"""An easing function that has a quartic curve.
.. figure:: images/plot_out_quart.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_quart`.
With image data, it is a moderate extension of the lighter areas
and compression of the darker ones.
.. figure:: images/ex_out_quart.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_quart` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - (1 - a) ** 4
[docs]
@register(eases)
@will_scale
def out_quint(a: ImgAry) -> ImgAry:
"""An easing function that has a quintic curve.
.. figure:: images/plot_out_quint.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_quint`.
With image data, it is a large extension of the lighter areas
and compression of the darker ones.
.. figure:: images/ex_out_quint.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_quint` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 1 - (1 - a) ** 5
[docs]
@register(eases)
@will_scale
def out_sin(a: ImgAry) -> ImgAry:
"""An easing function that has a sine curve.
.. figure:: images/plot_out_sin.png
:alt: A chart showing the action of the easing function.
The action of :func:`out_sin`.
With image data, it is a small extension of the lighter areas
and compression of the darker ones.
.. figure:: images/ex_out_sin.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`out_sin` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return np.sin(a * np.pi / 2)
# Ease in and out functions.
[docs]
@register(eases)
@will_scale
def in_out_back(a: ImgAry) -> ImgAry:
"""An easing function that backs up then overshoots.
.. figure:: images/plot_in_out_back.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_back`.
With image data, it extends the darker and lighter areas. The dip
into negative values and bounce over one can be a little awkward.
It's left to the calling application to decide how to handle it. In
the following example, values are just truncated at zero and one.
.. figure:: images/ex_in_out_back.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_back` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
c1 = 1.70158
c2 = c1 * 1.525
m = np.zeros(a.shape, bool)
m[a < .5] = True
a[m] = (2 * a[m]) ** 2 * ((c2 + 1) * 2 * a[m] - c2) / 2
a[~m] = ((2 * a[~m] - 2) ** 2 * ((c2 + 1) * (a[~m] * 2 - 2) + c2) + 2) / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_bounce(a: ImgAry) -> ImgAry:
"""An easing function that has a bounce
.. figure:: images/plot_in_out_bounce.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_bounce`.
With image data, it extends the darker and lighter areas. The dip
into negative values and bounce over one can be a little awkward.
It's left to the calling application to decide how to handle it. In
the following example, values are just truncated at zero and one.
.. figure:: images/ex_in_out_bounce.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_bounce` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[a < 0.5] = (1 - out_bounce(1 - 2 * a[a < 0.5])) / 2
a[a >= 0.5] = (1 + out_bounce(2 * a[a >= 0.5] - 1)) / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_circ(a: ImgAry) -> ImgAry:
"""An easing function that uses a circular curve to compress the
middle.
.. figure:: images/plot_in_out_circ.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_circ`.
With image data, it extends the darker and lighter areas. This
should not generate values outside of the original range.
.. figure:: images/ex_in_out_circ.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_circ` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
m = np.zeros(a.shape, bool)
m[a < .5] = True
a[m] = (1 - np.sqrt(1 - (2 * a[m]) ** 2)) / 2
a[~m] = (np.sqrt(1 - (-2 * a[~m] + 2) ** 2) + 1) / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_cos(a: ImgAry) -> ImgAry:
"""An easing function that uses a cosine curve to turn the make the
middle low and the edges high.
.. figure:: images/plot_in_out_cos.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_cos`.
With image data, it turns the midtones dark and the dark and light
become midtones. This should not generate values outside of the
original range.
.. figure:: images/ex_in_out_cos.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_cos` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return -1 * (np.sin(np.pi * a) - 1) / 2
[docs]
@register(eases)
@will_scale
def in_out_cubic(a: ImgAry) -> ImgAry:
"""An easing function that uses a cubic curve to compress the
middle.
.. figure:: images/plot_in_out_cubic.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_cubic`.
With image data, it extends the darker and lighter areas. This
should not generate values outside of the original range.
.. figure:: images/ex_in_out_cubic.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_cubic` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[a < .5] = 4 * a[a < .5] ** 3
a[a >= .5] = 1 - (-2 * a[a >= .5] + 2) ** 3 / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_elastic(a: ImgAry) -> ImgAry:
"""An easing function that uses a bouncy curve to compress the
middle.
.. figure:: images/plot_in_out_elastic.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_elastic`.
With image data, it extends the darker and lighter areas. The
dip into values below zero or bounce into values over one can
be a little awkward. It's left to the calling application to
decide how to handle it. In the following example, values are
just truncated at one.
.. figure:: images/ex_in_out_elastic.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_elastic` affects a simple
gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
c5 = (2 * np.pi) / 4.5
# Create masks for the array.
m1 = np.zeros(a.shape, bool)
m1[a < .5] = True
m1[a <= 0] = False
m2 = np.zeros(a.shape, bool)
m2[a >= .5] = True
m2[a >= 1] = False
# Run the easing function based on the masks.
a[m1] = -(2 ** (20 * a[m1] - 10) * np.sin((20 * a[m1] - 11.125) * c5))
a[m1] = a[m1] / 2
a[m2] = (2 ** (-20 * a[m2] + 10) * np.sin((20 * a[m2] - 11.125) * c5))
a[m2] = a[m2] / 2 + 1
return a
[docs]
@register(eases)
@will_scale
def in_out_expo(a: ImgAry) -> ImgAry:
"""An easing function that uses a exponential curve to compress the
middle.
.. figure:: images/plot_in_out_expo.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_expo`.
With image data, it extends the darker and lighter areas. This
should not generate values outside of the original range.
.. figure:: images/ex_in_out_expo.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_expo` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[np.logical_and(a > 0.0, a < 0.5)] = (
2 ** (20 * a[np.logical_and(a > 0.0, a < 0.5)] - 10) / 2
)
a[np.logical_and(a < 1.0, a >= 0.5)] = (
(2 - 2 ** (-20 * a[np.logical_and(a < 1.0, a >= 0.5)] + 10)) / 2
)
return a
[docs]
@register(eases)
@will_scale
def in_out_perlin(a: ImgAry) -> ImgAry:
"""An easing function that uses the easing equation from Ken
Perlin's "Improved Perlin Noise" papaer.
.. figure:: images/plot_in_out_perlin.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_perlin`.
With image data, it slightly extends the darker and lighter areas.
This should not generate values outside of the original range.
.. figure:: images/ex_in_out_perlin.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_perlin` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return 6 * a ** 5 - 15 * a ** 4 + 10 * a ** 3
[docs]
@register(eases)
@will_scale
def in_out_quad(a: ImgAry) -> ImgAry:
"""An easing function that uses a quadratic curve to compress the
middle.
.. figure:: images/plot_in_out_quad.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_quad`.
With image data, it extends the darker and lighter areas. This
should not generate values outside of the original range.
.. figure:: images/ex_in_out_quad.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_quad` affects a simple
gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
m = np.zeros(a.shape, bool)
m[a < .5] = True
a[m] = 2 * a[m] ** 2
a[~m] = 1 - (-2 * a[~m] + 2) ** 2 / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_quart(a: ImgAry) -> ImgAry:
"""An easing function that uses a quartic curve to compress the
middle.
.. figure:: images/plot_in_out_quart.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_quart`.
With image data, it extends the darker and lighter areas. This
should not generate values outside of the original range.
.. figure:: images/ex_in_out_quart.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_quart` affects a simple
gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[a < .5] = 8 * a[a < .5] ** 4
a[a >= .5] = 1 - (-2 * a[a >= .5] + 2) ** 4 / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_quint(a: ImgAry) -> ImgAry:
"""An easing function that uses a quintic curve to compress the
middle.
.. figure:: images/plot_in_out_quint.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_quint`.
With image data, it greatly extends the darker and lighter areas.
This should not generate values outside of the original range.
.. figure:: images/ex_in_out_quint.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_quint` affects a simple
gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a[a < .5] = 16 * a[a < .5] ** 5
a[a >= .5] = 1 - (-2 * a[a >= .5] + 2) ** 5 / 2
return a
[docs]
@register(eases)
@will_scale
def in_out_sin(a: ImgAry) -> ImgAry:
"""An easing function that uses a sine curve to compress the
middle.
.. figure:: images/plot_in_out_sin.png
:alt: A chart showing the action of the easing function.
The action of :func:`in_out_sin`.
With image data, it slightly extends the darker and lighter areas.
This should not generate values outside of the original range.
.. figure:: images/ex_in_out_sin.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`in_out_sin` affects a simple gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
return -1 * (np.cos(np.pi * a) - 1) / 2
# Ease mid functions.
[docs]
@register(eases)
@will_scale
def mid_bump_linear(a: ImgAry) -> ImgAry:
"""An easing function that makes the middle of the range the peak
of the values.
.. figure:: images/plot_mid_bump_linear.png
:alt: A chart showing the action of the easing function.
The action of :func:`mid_bump_linear`.
With image data, it makes the midtones light and the edges dark.
.. figure:: images/ex_mid_bump_linear.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`mid_bump_linear` affects a simple
gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a = np.abs(a - .5)
m = np.zeros(a.shape, bool)
m[a < .25] = True
a[m] = (.25 - a[m]) * 4
a[~m] = 0
return a
[docs]
@register(eases)
@will_scale
def mid_bump_sin(a: ImgAry) -> ImgAry:
"""An easing function that makes the middle of the range the peak
of the values.
.. figure:: images/plot_mid_bump_sin.png
:alt: A chart showing the action of the easing function.
The action of :func:`mid_bump_sin`.
With image data, it makes the midtones light and the edges dark.
.. figure:: images/ex_mid_bump_sin.png
:alt: An example of the easing function affecting a gradient.
An example of how :func:`mid_bump_sin` affects a simple
gradient.
:param a: An array of image data.
:return: The eased data as a :class:`numpy.ndarray`.
:rtype: numpy.ndarray
"""
a = np.abs(a - .5)
m = np.zeros(a.shape, bool)
m[a < .25] = True
a[m] = (.25 - a[m]) * 4
a[~m] = 0
return in_out_sin(a)
if __name__ == '__main__':
from pjimg.util.debug import print_array
a = np.array([
[
[0.00, 0.25, 0.50, 0.75, 1.00, ],
[0.25, 0.50, 0.75, 1.00, 0.75, ],
[0.50, 0.75, 1.00, 0.75, 0.50, ],
[0.75, 1.00, 0.75, 0.50, 0.25, ],
[1.00, 0.75, 0.50, 0.25, 0.00, ],
],
], dtype=float)
a = in_out_bounce(a)
print_array(a, 1)