Progress.java

package swingtree.animation;

/**
 *  Represents the progress snapshot of an animation in terms of numbers between 0 and 1
 *  that describe how far the animation has progressed between its start and end.
 *  The different methods of this interface provide various ways to interpret the progress
 *  of an animation, such as linearly, sinusoidally, or cyclically.
 */
public interface Progress
{
    /**
     *  Exposes the progress of the animation state, which is a number between 0 and 1
     *  that represents how far the animation has progressed between its start and end.
     *  Note that an animation may also regress, in which case the states will
     *  transition from 1 to 0 instead of from 0 to 1.
     *  See {@link Stride} for more information.
     *
     * @return The animation progress in terms of a number between 0 and 1,
     *         where 0.5 means the animation is halfway through, and 1 means the animation completed.
     */
    double progress();

    /**
     *  The animation progress in the form of a value linearly growing from {@code start} to {@code end}
     *  based on the equation {@code start + (end - start) * progress()}.
     *  At the beginning of the animation, the value is {@code start}, at the end of the animation, the value is {@code end}.
     *
     * @param start The start value of the animation.
     * @param end The end value of the animation.
     * @return The animation progress in terms of a number between {@code start} and {@code end}.
     */
    default double progress( double start, double end ) {
        return start + (end - start) * progress();
    }

    /**
     *  The animation progress in the form of a value linearly growing from 1 to 0
     *  based on the equation {@code 1 - progress()}.
     *  At the beginning of the animation, the value is 1, at the end of the animation, the value is 0.
     *
     * @return The animation progress in terms of a number between 0 and 1, where 0.5 means the animation is halfway through.
     */
    default double regress() {
        return 1 - progress();
    }

    /**
     *  The animation regression in the form of a value linearly growing from {@code start} to {@code end}.
     *  This method is equivalent to {@code progress(end, start)}.
     *
     * @param end The end value of the animation.
     * @param start The start value of the animation.
     * @return The animation progress in terms of a number between {@code start} and {@code end}.
     */
    default double regress( double end, double start ) {
        return start + (end - start) * regress();
    }

    /**
     *  A sine wave oscillating between 0 and 1 and back to 0 once per iteration.
     *  At the beginning of the animation, the value is 0, at the end of the animation, the value is 0 again,
     *  and when the animation is halfway through, the value is 1.
     *
     * @return The animation progress in terms of a number between 0 and 1, where 1 means the animation is halfway through.
     */
    default double pulse() {
        return Math.sin(Math.PI * progress());
    }

    /**
     *  A sine wave oscillating between {@code start} and {@code peak} and back to {@code start} once per iteration.
     *  At the beginning of the animation, the value is {@code start}, at the end of the animation,
     *  the value is {@code start} again,
     *  and when the animation is halfway through, the value is {@code peak}.
     *
     *  @param start The start value of the sine wave.
     *  @param peak The peak value of the sine wave.
     *  @return The animation progress in terms of a number between {@code start} and {@code end}, where {@code end} means the animation is halfway through.
     */
    default double pulse( double start, double peak ) {
        return start + (peak - start) * pulse();
    }

    /**
     *   The animation progress in the form of quickly growing sine wave front going from 0 to 1
     *   based on the equation {@code sin(PI * progress() / 2)}.
     *   Just like the value returned by {@link #progress()}
     *   the {@link #jumpIn()} value starts at 0 and ends at 1,
     *   however the crucial difference is that the {@link #jumpIn()} value
     *   grows according to a sine wave, which makes certain animations look more natural. <br>
     *   The returned value will grow quickly at the beginning and slowly at the end, hence the name.
     *
     * @return The animation progress in the form of peaking sine wave growing from 0 to 1.
     */
    default double jumpIn() {
        return Math.sin(Math.PI * progress() / 2);
    }

    /**
     *   The animation progress in the form of peaking sine wave growing from {@code start} to {@code end}
     *   based on the equation {@code start + (end - start) * jumpIn()}.
     *   Just like the value returned by {@link #progress()}
     *   the {@link #jumpIn()} value starts at {@code start} and ends at {@code end},
     *   however the crucial difference is that the {@link #jumpIn()} value
     *   grows according to a sine wave, which makes certain animations look more natural. <br>
     *   The returned value will grow quickly at the beginning and slowly at the end, hence the name.
     *
     * @param start The start value of the animation.
     * @param end The end value of the animation.
     * @return The animation progress in the form of peaking sine wave growing from {@code start} to {@code end}.
     */
    default double jumpIn( double start, double end ) {
        return start + (end - start) * jumpIn();
    }

    /**
     *   The animation progress in the form of peaking sine wave growing from 1 to 0
     *   based on the equation {@code sin(PI * (1 - progress()) / 2)}.
     *   Just like the value returned by {@link #progress()}
     *   the {@link #jumpOut()} value starts at 1 and ends at 0,
     *   however the crucial difference is that the {@link #fadeOut()} value
     *   grows according to a sine wave, which makes certain animations look more natural.
     *
     * @return The animation progress in the form of peaking sine wave growing from 1 to 0.
     */
    default double jumpOut() {
        return Math.sin(Math.PI * (1 - progress()) / 2);
    }

    /**
     *   The animation progress in the form of a initially quickly changing sine wave
     *   going from {@code start} to {@code end}
     *   based on the equation {@code end + (start - end) * jumpOut()}.
     *   Just like the value returned by {@link #progress(double, double)}
     *   the {@link #jumpOut(double, double)} value starts at {@code start} and ends at {@code end},
     *   however the crucial difference is that the {@link #jumpOut(double, double)} value
     *   changes according to a sine wave, which makes certain animations look more natural.
     *
     * @param end The end value of the animation,
     * @param start The start value of the animation.
     * @return The animation progress in the form of peaking sine wave growing from {@code start} to {@code end}.
     */
    default double jumpOut( double end, double start ) {
        return end + (start - end) * jumpOut();
    }

    /**
     *   The animation progress in the form of peaking sine wave growing from 0 to 1
     *   based on the equation
     *   {@code 0.5 * (1 + Math.sin( Math.PI * (progress() - 0.5) ) )}
     *   Just like the value returned by {@link #progress()}
     *   the {@link #fadeIn()} value starts at 0 and ends at 1,
     *   however the crucial difference is that the {@link #fadeIn()} value
     *   grows according to a sine wave, which makes certain animations look more natural. <br>
     *   The difference between this method and {@link #jumpIn()} is that the returned
     *   value grows slower at the beginning, where {@link #jumpIn()} grows faster initially.
     *
     * @return The animation progress in the form of peaking sine wave growing from 0 to 1.
     */
    default double fadeIn() {
        return 0.5 * (1 + Math.sin( Math.PI * (progress() - 0.5) ));
    }

    /**
     *   The animation progress in the form of peaking sine wave growing from {@code start} to {@code end}
     *   based on the equation {@code start + (end - start) * fadeIn()}.
     *   Just like the value returned by {@link #progress()}
     *   the {@link #fadeIn()} value starts at {@code start} and ends at {@code end},
     *   however the crucial difference is that the {@link #fadeIn()} value
     *   grows according to a sine wave, which makes certain animations look more natural. <br>
     *   The difference between this method and {@link #jumpIn()} is that the returned
     *   value grows slower at the beginning, where {@link #jumpIn()} grows faster initially.
     *
     * @param start The start value of the animation.
     * @param end The end value of the animation.
     * @return The animation progress in the form of a wave growing from {@code start} to {@code end}.
     */
    default double fadeIn( double start, double end ) {
        return start + (end - start) * fadeIn();
    }

    /**
     *   The animation progress in the form of peaking sine wave growing from 1 to 0
     *   based on the equation {@code 1 - fadeIn()}.
     *   Just like the value returned by {@link #progress()}
     *   the {@link #fadeOut()} value starts at 1 and ends at 0,
     *   however the crucial difference is that the {@link #fadeOut()} value
     *   grows according to a sine wave, which makes certain animations look more natural. <br>
     *   The difference between this method and {@link #jumpOut()} is that the returned
     *   value grows slower at the beginning, where {@link #jumpOut()} grows faster initially.
     *
     * @return The animation progress in the form of wave growing from 1 to 0.
     */
    default double fadeOut() {
        return 1 - fadeIn();
    }

    /**
     *   The animation progress in the form of a sine wave going from {@code start} to {@code end}
     *   based on the equation {@code end + (start - end) * fadeOut()}.
     *   Just like the value returned by {@link #progress(double, double)}
     *   the {@link #fadeOut(double, double)} value starts at {@code start} and ends at {@code end},
     *   however the crucial difference is that the {@link #fadeOut(double, double)} value
     *   grows according to a sine wave, which makes certain animations look more natural. <br>
     *   The difference between this method and {@link #jumpOut()} is that the returned
     *   value grows slower at the beginning, whereas {@link #jumpOut()} grows faster initially.
     *
     * @param end The end value of the animation,
     * @param start The start value of the animation,
     * @return The animation progress in the form a sine wave going from {@code start} to {@code end}.
     */
    default double fadeOut( double end, double start ) {
        return end + (start - end) * fadeOut();
    }

    /**
     *  Defines the animation progress in terms of a number oscillating between 0, 1 and 0 once per iteration,
     *  meaning that when the animation starts, the value is 0, when it is halfway through, the value is 1,
     *  and when it is finished, the value is 0 again.
     *  <p>
     *  This is especially useful for animations that are supposed to be repeated
     *  or whose start and end values are the same (e.g. a fade-in and fade-out animation).
     *
     *  @return The animation progress in terms of a number between 0 and 1,
     *          where 1 means the animation is halfway through and 0 means the animation started or finished.
     */
    default double cycle() {
        // progress() is guaranteed to be between 0 and 1, where 1 means the animation completed.
        return 1 - Math.abs(2 * progress() - 1);
        // The result is guaranteed to be between 0 and 1, where 1 means the animation is
        // halfway through and 0 means the animation started or finished.
    }

    /**
     *  Defines the animation progress in terms of a number oscillating between 0, 1 and 0 once per iteration,
     *  meaning that when the animation starts, the value is 0, when it is halfway through, the value is 1,
     *  and when it is finished, the value is 0 again.
     *  <p>
     *  This is especially useful for animations that are supposed to be repeated
     *  or whose start and end values are the same (e.g. a fade-in and fade-out animation).
     *  <p>
     *  This method is similar to {@link #cycle()}, but it allows to offset the animation progress.
     *  This is useful for animations that are supposed to be repeated and whose start and end values are different
     *  (e.g. a fade-in and fade-out animation).
     *
     *  @param offset The offset of the animation progress which may be any number.
     *                The modulo operator is used to offset the animation progress
     *                in a way that it is always between 0 and 1.
     *  @return The animation progress in terms of a number between 0 and 1,
     *          where 1 means the animation is halfway through and 0 means the animation started or finished.
     */
    default double cyclePlus( double offset ) {
        double progress = (progress() + offset) % 1;
        if ( progress < 0 ) progress += 1;
        return 1 - Math.abs(2 * progress - 1);
    }

    /**
     *  Defines the animation progress in terms of a number oscillating between 0, 1 and 0 once per iteration,
     *  meaning that when the animation starts, the value is 0, when it is halfway through, the value is 1,
     *  and when it is finished, the value is 0 again.
     *  <p>
     *  This is especially useful for animations that are supposed to be repeated
     *  or whose start and end values are the same (e.g. a fade-in and fade-out animation).
     *  <p>
     *  This method is similar to the of {@link #cyclePlus(double)} but
     *  with the offset being subtracted instead of added.
     *  The returned values is similar to the one returned by {@link #cycle()},
     *  with the simple difference to offset the animation progress.
     *  This is useful for animations that are supposed to be repeated and whose start and end values are different
     *  (e.g. a fade-in and fade-out animation).
     *
     *  @param offset The offset of the animation progress which may be any number.
     *                The modulo operator is used to offset the animation progress
     *                in a way that it is always between 0 and 1.
     *  @return The animation progress in terms of a number between 0 and 1,
     *          where 1 means the animation is halfway through and 0 means the animation started or finished.
     */
    default double cycleMinus( double offset ) {
        double progress = ( progress() - offset ) % 1;
        if ( progress < 0 ) progress += 1;
        return 1 - Math.abs(2 * progress - 1);
    }

}